Repository: apache/hive
Pull request #5729: HIVE-28782: Avoid unsafe splits on URIs that might contain IPv6 literals
Author: login: difin
Labels: name: tests passed
Created: 2025-04-01T16:26:27Z | Merged: 2025-04-09T14:10:20Z

<!--
Thanks for sending a pull request!  Here are some tips for you:
  1. If this is your first time, please read our contributor guidelines: https://cwiki.apache.org/confluence/display/Hive/HowToContribute
  2. Ensure that you have created an issue on the Hive project JIRA: https://issues.apache.org/jira/projects/HIVE/summary
  3. Ensure you have added or run the appropriate tests for your PR: 
  4. If the PR is unfinished, add '[WIP]' in your PR title, e.g., '[WIP]HIVE-XXXXX:  Your PR title ...'.
  5. Be sure to keep the PR description updated to reflect all changes.
  6. Please write your PR title to summarize what this PR proposes.
  7. If possible, provide a concise example to reproduce the issue for a faster review.

-->

### What changes were proposed in this pull request?
<!--
Please clarify what changes you are proposing. The purpose of this section is to outline the changes and how this PR fixes the issue. 
If possible, please consider writing useful notes for better and faster reviews in your PR. See the examples below.
  1. If you refactor some codes with changing classes, showing the class hierarchy will help reviewers.
  2. If you fix some SQL features, you can provide some references of other DBMSes.
  3. If there is design documentation, please add the link.
  4. If there is a discussion in the mailing list, please add the link.
-->
Avoid unsafe splits by a colon symbol on URIs that might contain IPv6 literals.

### Why are the changes needed?
<!--
Please clarify why the changes are needed. For instance,
  1. If you propose a new API, clarify the use case for a new API.
  2. If you fix a bug, you can clarify why it is a bug.
-->
To support IPv6 in Hive.

### Does this PR introduce _any_ user-facing change?
<!--
Note that it means *any* user-facing change including all aspects such as the documentation fix.
If yes, please clarify the previous behavior and the change this PR proposes - provide the console output, description, screenshot and/or a reproducable example to show the behavior difference if possible.
If possible, please also clarify if this is a user-facing change compared to the released Hive versions or within the unreleased branches such as master.
If no, write 'No'.
-->
No

### Is the change a dependency upgrade?
<!--
If yes, please attach a file with output from mvn dependency:tree to validate a complete upgrade of dependency.
If no, write 'No'.
-->
No

### How was this patch tested?
<!--
If tests were added, say they were added here. Please make sure to add some test cases that check the changes thoroughly including negative and positive cases if possible.
If it was tested in a way different from regular unit tests, please clarify how you tested step by step, ideally copy and paste-able, so that other reviewers can test and check, and descendants can verify in the future.
If tests were not added, please describe why they were not added and/or why it was difficult to add.
-->
New unit tests.


Diff:
diff --git a/common/src/java/org/apache/hive/common/IPStackUtils.java b/common/src/java/org/apache/hive/common/IPStackUtils.java
index 7b24b8a07810..949b6f14be1b 100644
--- a/common/src/java/org/apache/hive/common/IPStackUtils.java
+++ b/common/src/java/org/apache/hive/common/IPStackUtils.java
@@ -20,6 +20,8 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import io.netty.util.NetUtil;
+import org.apache.commons.lang3.StringUtils;
+
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
@@ -219,4 +221,88 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort getHostAndPort(String input) {
+    String host;
+    int port;
+
+    if (StringUtils.isEmpty(input)) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    port = getPort(input.substring(colonIndex + 1));
+
+    // Check if the host is not null or empty
+    if (StringUtils.isEmpty(host) || host.equals("[]")) {
+      throw new IllegalArgumentException("Host address is null or empty.");
+    }
+
+    // Handle IPv6 addresses enclosed in square brackets (e.g., [IPv6]:port)
+    if (host.startsWith("[") && host.endsWith("]")) {
+      host = host.substring(1, host.length() - 1); // Remove the square brackets
+    }
+
+    return new HostPort(host, port);
+  }
+
+  /**
+   * Returns an integer representation of the port number.
+   * Also validates whether the given string represents a valid port number.
+   * A valid port number is an integer between 0 and 65535 inclusive.
+   *
+   * @param portString The string representing the port number.
+   * @return {@code int} the port number.
+   */
+  public static int getPort(String portString) {
+    if (StringUtils.isEmpty(portString)) {
+      throw new IllegalArgumentException("port is null or empty");
+    }
+
+    int port = Integer.parseInt(portString);
+    validatePort(port);
+    return port;
+  }
+  
+  private static void validatePort(int port) {
+    if (port < 0 || port > 65535) {
+      throw new IllegalArgumentException("Port number out of range (0-65535).");
+    }
+  }
+
+  public static class HostPort {
+
+    private final String hostname;
+    private final int port;
+
+    public HostPort(String hostname, int port) {
+      this.hostname = hostname;
+      this.port = port;
+    }
+
+    public String getHostname() {
+      return hostname;
+    }
+
+    public int getPort() {
+      return port;
+    }
+  }
 }
diff --git a/common/src/test/org/apache/hive/common/IPStackUtilsTest.java b/common/src/test/org/apache/hive/common/IPStackUtilsTest.java
index 4c89c0e90696..7b289ee275fa 100644
--- a/common/src/test/org/apache/hive/common/IPStackUtilsTest.java
+++ b/common/src/test/org/apache/hive/common/IPStackUtilsTest.java
@@ -79,34 +79,12 @@ void testIPv4WildcardWhenIPv6IsNotPreferred() {
   }
 
   @Test
-  void testConcatHostPortIPv4Host() {
+  void testConcatHostPort() {
     assertEquals("192.168.1.1:8080", IPStackUtils.concatHostPort("192.168.1.1", 8080));
-  }
-
-  @Test
-  void testConcatHostPortIPv6Host() {
     assertEquals("[2001:db8::1]:8080", IPStackUtils.concatHostPort("2001:db8::1", 8080));
-  }
-
-  @Test
-  void testConcatHostPortIPv6Loopback() {
     assertEquals("[::1]:9090", IPStackUtils.concatHostPort("::1", 9090));
-  }
-
-  @Test
-  void testConcatHostPortHostname() {
     assertEquals("example.com:443", IPStackUtils.concatHostPort("example.com", 443));
   }
-
-  @Test
-  void testConcatHostPortLoobackIPv4() {
-    assertEquals("127.0.0.1:3306", IPStackUtils.concatHostPort("127.0.0.1", 3306));
-  }
-
-  @Test
-  void testConcatHostPortLoopbackIPv6() {
-    assertEquals("[::1]:3306", IPStackUtils.concatHostPort("::1", 3306));
-  }
   
   @Test
   void testWildcardWhenIPv4StackIsForcedAndIPv4WildcardProvided() {
@@ -164,20 +142,68 @@ void testWildcardWhenIPv6IsNotPreferredAndIPv6WildcardProvided() {
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv4AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("192.168.1.1");
-    assertEquals("192.168.1.1", result);
+  void testAdaptWildcardAddress() {
+    assertEquals("192.168.1.1", IPStackUtils.adaptWildcardAddress("192.168.1.1"));
+    assertEquals("2001:db8::1", IPStackUtils.adaptWildcardAddress("2001:db8::1"));
+    assertEquals("example.com", IPStackUtils.adaptWildcardAddress("example.com"));
+  }
+
+    // Test cases for getHostAndPort method
+
+  @Test
+  void testGetHostAndPortWithIPv4() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("192.168.1.1:8080");
+    assertEquals("192.168.1.1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("[2001:0db8::1]:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithoutSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("2001:0db8::1:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithHostname() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("example.com:80");
+    assertEquals("example.com", result.getHostname());
+    assertEquals(80, result.getPort());
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv6AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("2001:db8::1");
-    assertEquals("2001:db8::1", result);
+  void testGetHostPortWithInvalidAndPort() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1:70000"),
+        "Port number out of range (0-65535).");
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1"),
+        "Input does not contain a port.");
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort(":8080"),
+        "Host address is null or empty.");
+  }
+
+  // Test cases for getPort method
+
+  @Test
+  void testGetPort() {
+    assertEquals(8080, IPStackUtils.getPort("8080"));
+    assertEquals(65535, IPStackUtils.getPort("65535"));
+    assertEquals(0, IPStackUtils.getPort("0"));
   }
 
   @Test
-  void testWildcardWhenHostnameIsProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("example.com");
-    assertEquals("example.com", result);
+  void testGetPortWithInvalidPort() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getPort("70000"),
+        "Port number out of range (0-65535).");
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getPort("-1"),
+        "Port number out of range (0-65535).");
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getPort("abc"),
+        "For input string: \"abc\"");
   }
 }
\ No newline at end of file
diff --git a/jdbc/src/java/org/apache/hive/jdbc/ZooKeeperHiveClientHelper.java b/jdbc/src/java/org/apache/hive/jdbc/ZooKeeperHiveClientHelper.java
index dfe21e71331c..513113bb077f 100644
--- a/jdbc/src/java/org/apache/hive/jdbc/ZooKeeperHiveClientHelper.java
+++ b/jdbc/src/java/org/apache/hive/jdbc/ZooKeeperHiveClientHelper.java
@@ -34,6 +34,7 @@
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hive.common.SSLZookeeperFactory;
 import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hive.common.IPStackUtils;
 import org.apache.hive.jdbc.Utils.JdbcConnectionParams;
 import org.apache.hive.service.server.HS2ActivePassiveHARegistry;
 import org.apache.hive.service.server.HS2ActivePassiveHARegistryClient;
@@ -178,12 +179,13 @@ private static void updateParamsWithZKServerNode(JdbcConnectionParams connParams
     // it must be the server uri added by an older version HS2
     Matcher matcher = kvPattern.matcher(dataStr);
     if ((dataStr != null) && (!matcher.find())) {
-      String[] split = dataStr.split(":");
-      if (split.length != 2) {
+      try {
+        IPStackUtils.HostPort hostPort = IPStackUtils.getHostAndPort(dataStr);
+        connParams.setHost(hostPort.getHostname());
+        connParams.setPort(hostPort.getPort());
+      } catch (Exception e) {
         throw new ZooKeeperHiveClientException("Unable to parse HiveServer2 URI from ZooKeeper data: " + dataStr);
       }
-      connParams.setHost(split[0]);
-      connParams.setPort(Integer.parseInt(split[1]));
     } else {
       applyConfs(dataStr, connParams);
     }
diff --git a/jdbc/src/test/org/apache/hive/jdbc/ZooKeeperHiveClientHelperTest.java b/jdbc/src/test/org/apache/hive/jdbc/ZooKeeperHiveClientHelperTest.java
new file mode 100644
index 000000000000..7b759482efce
--- /dev/null
+++ b/jdbc/src/test/org/apache/hive/jdbc/ZooKeeperHiveClientHelperTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.hive.jdbc;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.GetDataBuilder;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.Mock;
+
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(Parameterized.class)
+public class ZooKeeperHiveClientHelperTest {
+
+  private Utils.JdbcConnectionParams connParams;
+  private CuratorFramework mockZooKeeperClient;
+
+  @Mock
+  private GetDataBuilder mockGetDataBuilder;
+
+  private final String input;
+  private final String expectedHost;
+  private final int expectedPort;
+  private final boolean expectException;
+
+  public ZooKeeperHiveClientHelperTest(String input, String expectedHost, int expectedPort, boolean expectException) {
+    this.input = input;
+    this.expectedHost = expectedHost;
+    this.expectedPort = expectedPort;
+    this.expectException = expectException;
+  }
+
+  @Parameterized.Parameters
+  public static Collection<Object[]> data() {
+    return Arrays.asList(new Object[][]{
+        // Valid cases
+        {"localhost:9090", "localhost", 9090, false},        // Hostname
+        {"192.168.1.1:8080", "192.168.1.1", 8080, false},    // IPv4
+        {"[2001:db8::1]:1234", "2001:db8::1", 1234, false},  // IPv6 with square brackets
+        {"2001:db8::1:5678", "2001:db8::1", 5678, false},    // IPv6 without square brackets
+
+        // Invalid cases (Invalid host and port format)
+        {"localhost", null, 0, true},         // Missing port
+        {":9090", null, 0, true},             // Missing hostname
+        {"192.168.1.1:", null, 0, true},      // Missing port after IPv4
+        {"[2001:db8::1]", null, 0, true},     // Missing port after IPv6 with square brackets
+        {"invalid_host:port", null, 0, true}  // Invalid host
+    });
+  }
+
+  @Before
+  public void setUp() {
+    connParams = new Utils.JdbcConnectionParams();
+    mockZooKeeperClient = mock(CuratorFramework.class);
+    mockGetDataBuilder = mock(GetDataBuilder.class);
+
+    // Mock the getData() method to return mockGetDataBuilder
+    when(mockZooKeeperClient.getData()).thenReturn(mockGetDataBuilder);
+  }
+
+  @Test
+  public void testUpdateParamsWithZKServerNode_HostPortParsing_Success() throws Exception {
+    String serverNode = "testServerNode";
+
+    // Mock the behavior of getData().forPath() to return the data bytes
+    when(mockGetDataBuilder.forPath(anyString())).thenReturn(input.getBytes(StandardCharsets.UTF_8));
+
+    // Access the private method using reflection
+    Method updateParamsMethod = ZooKeeperHiveClientHelper.class.getDeclaredMethod(
+        "updateParamsWithZKServerNode", Utils.JdbcConnectionParams.class, CuratorFramework.class, String.class);
+
+    // Make the private method accessible
+    updateParamsMethod.setAccessible(true);
+    
+    try {
+      // Call the private method under test
+      updateParamsMethod.invoke(null, connParams, mockZooKeeperClient, serverNode);
+
+      if (expectException) {
+        fail("Expected IllegalArgumentException or ZooKeeperHiveClientException due to invalid format.");
+      } else {
+        assertEquals(connParams.getHost(), expectedHost);
+        assertEquals(connParams.getPort(), expectedPort);
+      }
+    } catch (Exception e) {
+      // We expect exceptions for invalid input, so the test passes if we catch them
+      assertTrue(expectException && 
+          e.getCause() instanceof IllegalArgumentException || e.getCause() instanceof ZooKeeperHiveClientException);
+    }
+  }
+}
\ No newline at end of file
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java b/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java
index 55ecbb45b9ea..197196e0085c 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java
@@ -71,20 +71,21 @@ public HiveLockObjectData(String queryId, String lockTime, String lockMode, Stri
     /**
      * Constructor
      * 
-     * @param data String of the form "queryId:lockTime:lockMode:queryStr". 
-     * No ':' characters are allowed in any of the components.
+     * @param data String of the form "queryId:lockTime:lockMode:queryStr[:clientIp]". 
+     * No ':' characters are allowed in any of the first four components, but the clientIp can contain colons (IPv6).
      */
     public HiveLockObjectData(String data) {
       if (data == null) {
         return;
       }
 
-      String[] elem = data.split(":");
+      String[] elem = data.split(":", 5);
       queryId = elem[0];
       lockTime = StringInternUtils.internIfNotNull(elem[1]);
       lockMode = elem[2];
       queryStr = StringInternUtils.internIfNotNull(elem[3]);
       if (elem.length >= 5) {
+        // The client IP is the suffix after the 4th colon, this can be IPv6 with colons
         clientIp = elem[4];
       }
     }
diff --git a/ql/src/test/org/apache/hadoop/hive/ql/lockmgr/TestHiveLockObject.java b/ql/src/test/org/apache/hadoop/hive/ql/lockmgr/TestHiveLockObject.java
index 52f86bb0956a..3fe1bb4829bd 100644
--- a/ql/src/test/org/apache/hadoop/hive/ql/lockmgr/TestHiveLockObject.java
+++ b/ql/src/test/org/apache/hadoop/hive/ql/lockmgr/TestHiveLockObject.java
@@ -18,50 +18,103 @@
 
 package org.apache.hadoop.hive.ql.lockmgr;
 
-import org.junit.Assert;
-
 import org.apache.hadoop.hive.conf.HiveConf;
 import org.apache.hadoop.hive.ql.lockmgr.HiveLockObject.HiveLockObjectData;
 import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+@RunWith(Enclosed.class)
 public class TestHiveLockObject {
 
-  private HiveConf conf = new HiveConf();
+  public static class TestHiveLockObjectNonParametrized {
+    private final HiveConf conf = new HiveConf();
+
+    @Test
+    public void testEqualsAndHashCode() {
+      HiveLockObjectData data1 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
+          "select * from mytable", conf);
+      HiveLockObjectData data2 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
+          "select * from mytable", conf);
+      assertEquals(data1, data2);
+      assertEquals(data1.hashCode(), data2.hashCode());
 
-  @Test
-  public void testEqualsAndHashCode() {
-    HiveLockObjectData data1 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
-        "select * from mytable", conf);
-    HiveLockObjectData data2 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
-        "select * from mytable", conf);
-    Assert.assertEquals(data1, data2);
-    Assert.assertEquals(data1.hashCode(), data2.hashCode());
+      HiveLockObject obj1 = new HiveLockObject("mytable", data1);
+      HiveLockObject obj2 = new HiveLockObject("mytable", data2);
+      assertEquals(obj1, obj2);
+      assertEquals(obj1.hashCode(), obj2.hashCode());
+    }
 
-    HiveLockObject obj1 = new HiveLockObject("mytable", data1);
-    HiveLockObject obj2 = new HiveLockObject("mytable", data2);
-    Assert.assertEquals(obj1, obj2);
-    Assert.assertEquals(obj1.hashCode(), obj2.hashCode());
+    @Test
+    public void testTruncate() {
+      conf.setIntVar(HiveConf.ConfVars.HIVE_LOCK_QUERY_STRING_MAX_LENGTH, 1000000);
+      HiveLockObjectData data0 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
+          "01234567890", conf);
+      assertEquals("With default settings query string should not be truncated",
+          11, data0.getQueryStr().length());
+      conf.setIntVar(HiveConf.ConfVars.HIVE_LOCK_QUERY_STRING_MAX_LENGTH, 10);
+      HiveLockObjectData data1 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
+          "01234567890", conf);
+      HiveLockObjectData data2 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
+          "0123456789", conf);
+      HiveLockObjectData data3 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
+          "012345678", conf);
+      HiveLockObjectData data4 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
+          null, conf);
+      assertEquals("Long string truncation failed", 10, data1.getQueryStr().length());
+      assertEquals("String truncation failed", 10, data2.getQueryStr().length());
+      assertEquals("Short string should not be truncated", 9, data3.getQueryStr().length());
+      assertNull("Null query string handling failed", data4.getQueryStr());
+    }
   }
 
-  @Test
-  public void testTruncate() {
-    conf.setIntVar(HiveConf.ConfVars.HIVE_LOCK_QUERY_STRING_MAX_LENGTH, 1000000);
-    HiveLockObjectData data0 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
-        "01234567890", conf);
-    Assert.assertEquals("With default settings query string should not be truncated",
-        data0.getQueryStr().length(), 11);
-    conf.setIntVar(HiveConf.ConfVars.HIVE_LOCK_QUERY_STRING_MAX_LENGTH, 10);
-    HiveLockObjectData data1 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
-        "01234567890", conf);
-    HiveLockObjectData data2 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
-        "0123456789", conf);
-    HiveLockObjectData data3 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
-        "012345678", conf);
-    HiveLockObjectData data4 = new HiveLockObjectData("ID1", "SHARED", "1997-07-01",
-        null, conf);
-    Assert.assertEquals("Long string truncation failed", data1.getQueryStr().length(), 10);
-    Assert.assertEquals("String truncation failed", data2.getQueryStr().length(), 10);
-    Assert.assertEquals("Short string should not be truncated", data3.getQueryStr().length(), 9);
-    Assert.assertNull("Null query string handling failed", data4.getQueryStr());
+  @RunWith(Parameterized.class)
+  public static class TestHiveLockObjectParametrized {
+
+    private final String data;
+    private final String expectedQueryId;
+    private final String expectedLockTime;
+    private final String expectedLockMode;
+    private final String expectedQueryStr;
+    private final String expectedClientIp;
+
+    public TestHiveLockObjectParametrized(String data, String expectedQueryId, String expectedLockTime,
+                              String expectedLockMode, String expectedQueryStr, String expectedClientIp) {
+      this.data = data;
+      this.expectedQueryId = expectedQueryId;
+      this.expectedLockTime = expectedLockTime;
+      this.expectedLockMode = expectedLockMode;
+      this.expectedQueryStr = expectedQueryStr;
+      this.expectedClientIp = expectedClientIp;
+    }
+
+    // Method to supply the parameters for the parameterized test
+    @Parameterized.Parameters
+    public static Collection<Object[]> data() {
+      return Arrays.asList(new Object[][] {
+          { "query1:2025-03-31:EXPLICIT:SELECT * FROM table", "query1", "2025-03-31", "EXPLICIT", "SELECT * FROM table", null },
+          { "query2:2025-03-31:EXPLICIT:SELECT * FROM table:192.168.0.1", "query2", "2025-03-31", "EXPLICIT", "SELECT * FROM table", "192.168.0.1" },
+          { "query3:2025-03-31:EXPLICIT:SELECT * FROM table:2001:0db8:85a3:0000:0000:8a2e:0370:7334", "query3", "2025-03-31", "EXPLICIT", "SELECT * FROM table", "2001:0db8:85a3:0000:0000:8a2e:0370:7334" },
+          { "query5:2025-03-31:EXPLICIT:SELECT * FROM table:some.company.com", "query5", "2025-03-31", "EXPLICIT", "SELECT * FROM table", "some.company.com" }
+      });
+    }
+    
+    @Test
+    public void testConstructor() {
+      HiveLockObjectData lockObjectData = new HiveLockObjectData(data);
+
+      assertEquals("queryId should match", expectedQueryId, lockObjectData.getQueryId());
+      assertEquals("lockTime should match", expectedLockTime, lockObjectData.getLockTime());
+      assertEquals("lockMode should match", expectedLockMode, lockObjectData.getLockMode());
+      assertEquals("queryStr should match", expectedQueryStr, lockObjectData.getQueryStr());
+      assertEquals("clientIp should match", expectedClientIp, lockObjectData.getClientIp());
+    }
   }
 }
diff --git a/service/src/java/org/apache/hive/service/server/HS2ActivePassiveHARegistry.java b/service/src/java/org/apache/hive/service/server/HS2ActivePassiveHARegistry.java
index f7dbe3c48316..bf0f53636ec4 100644
--- a/service/src/java/org/apache/hive/service/server/HS2ActivePassiveHARegistry.java
+++ b/service/src/java/org/apache/hive/service/server/HS2ActivePassiveHARegistry.java
@@ -42,8 +42,8 @@
 import org.apache.hadoop.registry.client.binding.RegistryTypeUtils;
 import org.apache.hadoop.registry.client.types.Endpoint;
 import org.apache.hadoop.registry.client.types.ServiceRecord;
-import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.yarn.api.records.ApplicationId;
+import org.apache.hive.common.IPStackUtils;
 import org.apache.hive.service.ServiceException;
 import org.apache.hive.service.auth.AuthType;
 import org.slf4j.Logger;
@@ -173,9 +173,9 @@ private void addEndpointToServiceRecord(
 
   private void updateEndpoint(final ServiceRecord srv, final String endpointName) {
     final String instanceUri = srv.get(INSTANCE_URI_CONFIG);
-    final String[] tokens = instanceUri.split(":");
-    final String hostname = tokens[0];
-    final int port = Integer.parseInt(tokens[1]);
+    IPStackUtils.HostPort hostPort = IPStackUtils.getHostAndPort(instanceUri);
+    final String hostname = hostPort.getHostname();
+    final int port = hostPort.getPort();
     Endpoint urlEndpoint = RegistryTypeUtils.ipcEndpoint(endpointName, new InetSocketAddress(hostname, port));
     srv.addInternalEndpoint(urlEndpoint);
     LOG.info("Added {} endpoint to service record", urlEndpoint);


Reviews:
user: login: kokila-19
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T03:10:45Z
user: login: kokila-19
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T03:39:19Z
user: login: copilot-pull-request-reviewer[bot]
body: 

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.


<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**jdbc/src/test/org/apache/hive/jdbc/ZooKeeperHiveClientHelperTest.java:116**
* The boolean expression in the catch block may be misinterpreted due to operator precedence. Consider adding parentheses to ensure that the check is evaluated as: assertTrue(expectException && (e.getCause() instanceof IllegalArgumentException || e.getCause() instanceof ZooKeeperHiveClientException)).
```
assertTrue(expectException && e.getCause() instanceof IllegalArgumentException || e.getCause() instanceof ZooKeeperHiveClientException);
```
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-04T06:42:36Z
user: login: ayushtkn
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T07:15:33Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T19:51:01Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T20:22:56Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T20:31:30Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T20:40:08Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T21:13:06Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T21:14:58Z
user: login: ayushtkn
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-07T11:33:15Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T13:29:11Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T13:33:20Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T13:48:13Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T13:51:14Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T13:52:30Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T14:14:16Z
user: login: ayushtkn
body: Minor comments, rest LGTM
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-08T02:20:00Z
user: login: kokila-19
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T07:33:11Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T21:09:52Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T21:14:22Z
user: login: difin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T21:17:21Z

Review comments:
diff_hunk: @@ -219,4 +219,94 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (1-65535).");
+    }
+    port = Integer.parseInt(portStr);
+
+    // Handle IPv6 addresses enclosed in square brackets (e.g., [IPv6]:port)
+    if (host.startsWith("[") && host.endsWith("]")) {
+      host = host.substring(1, host.length() - 1); // Remove the square brackets
+    }
+
+    // Check if the host is not null or empty
+    if (host == null || host.isEmpty()) {
+      throw new IllegalArgumentException("Host address is null or empty.");
+    }
+
+    return new HostPort(host, port);
+  }
+
+  /**
+   * Validates whether the given string represents a valid port number.
+   * A valid port number is an integer between 0 and 65535 inclusive.
+   *
+   * @param portString The string representing the port number to be validated.
+   * @return {@code true} if the port string is a valid port number, otherwise {@code false}.
+   */
+  public static boolean isValidPort(String portString) {
+    if (portString == null || portString.isEmpty()) {
+      return false;
+    }
+
+    // Regex to check if the port number is between 0 and 65535
+    String regex = "^(0|[1-9][0-9]{0,4})$";
+
+    if (portString.matches(regex)) {
+      int port = Integer.parseInt(portString);
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: kokila-19
body: Here, the portString is parsed twice , one using regex and another to convert from string to int. 
Its redundant as it would be efficient to use any one. 
One possible way is to use 
```
try {
   int port = Integer.parseInt(portString);
   return port >= 0 && port <= 65535;
} catch (NumberFormatException e) {
   return false;
}
```
created_at: 2025-04-04T03:10:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,94 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (1-65535).");
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: kokila-19
body: The current isValidPort method allows port 0, but as per the error message **"Port number out of range (1-65535)"**, port 0 is reserved and should not be used. 
To make the logic consistent with the error message and for proper validation, the check can be updated from
 **return port >= 0 && port <= 65535;**
 to 
  **return port >= 1 && port <= 65535;**
created_at: 2025-04-04T03:39:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -173,9 +173,9 @@ private void addEndpointToServiceRecord(
 
   private void updateEndpoint(final ServiceRecord srv, final String endpointName) {
     final String instanceUri = srv.get(INSTANCE_URI_CONFIG);
-    final String[] tokens = instanceUri.split(":");
-    final String hostname = tokens[0];
-    final int port = Integer.parseInt(tokens[1]);
+    IPStackUtils.HostPort hostPort = IPStackUtils.splitHostPort(instanceUri);
+    final String hostname = hostPort.getHostname();
+    final int port = hostPort.getPort();
path: service/src/java/org/apache/hive/service/server/HS2ActivePassiveHARegistry.java
user: login: ayushtkn
body: Does something like this work?
```
    final URI instanceUri  = new URI("//" + srv.get(INSTANCE_URI_CONFIG)); ;
    final String hostname = instanceUri.getHost();
    final int port = instanceUri.getPort();
```
created_at: 2025-04-04T06:55:41Z
author_association: MEMBER
diff_hunk: @@ -85,7 +85,9 @@ public HiveLockObjectData(String data) {
       lockMode = elem[2];
       queryStr = StringInternUtils.internIfNotNull(elem[3]);
       if (elem.length >= 5) {
-        clientIp = elem[4];
+        String prefix = queryId + ":" + lockTime + ":" + lockMode + ":" + queryStr + ":";
+        // The client IP is the suffix after the 4th colon, this can be IPv6 with colons
+        clientIp = data.substring(data.indexOf(prefix) + prefix.length());
path: ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java
user: login: ayushtkn
body: ```
clientIp = data.substring(prefix.length());
```
`data.indexOf(prefix) ` this would be 0 always, If I am catching it right
created_at: 2025-04-04T07:00:38Z
author_association: MEMBER
diff_hunk: @@ -85,7 +85,9 @@ public HiveLockObjectData(String data) {
       lockMode = elem[2];
       queryStr = StringInternUtils.internIfNotNull(elem[3]);
       if (elem.length >= 5) {
-        clientIp = elem[4];
path: ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java
user: login: ayushtkn
body: if we just do this above with split, will this work automatically?
```
      String[] elem = data.split(":", 5);
```

if this works we can avoid the prefix calculation & stuff like that
created_at: 2025-04-04T07:03:41Z
author_association: MEMBER
diff_hunk: @@ -178,12 +179,13 @@ private static void updateParamsWithZKServerNode(JdbcConnectionParams connParams
     // it must be the server uri added by an older version HS2
     Matcher matcher = kvPattern.matcher(dataStr);
     if ((dataStr != null) && (!matcher.find())) {
-      String[] split = dataStr.split(":");
-      if (split.length != 2) {
+      try {
+        IPStackUtils.HostPort hostPort = IPStackUtils.splitHostPort(dataStr);
+        connParams.setHost(hostPort.getHostname());
+        connParams.setPort(hostPort.getPort());
+      } catch (Exception e) {
         throw new ZooKeeperHiveClientException("Unable to parse HiveServer2 URI from ZooKeeper data: " + dataStr);
       }
-      connParams.setHost(split[0]);
-      connParams.setPort(Integer.parseInt(split[1]));
path: jdbc/src/java/org/apache/hive/jdbc/ZooKeeperHiveClientHelper.java
user: login: ayushtkn
body: I think there is already a Util if the URL thing with // doesn't work, can you check once
```
HostAndPort hostAndPort = HostAndPort.fromString(instanceUri);
String hostname = hostAndPort.getHost();
int port = hostAndPort.getPort();
```
created_at: 2025-04-04T07:15:17Z
author_association: MEMBER
diff_hunk: @@ -173,9 +173,9 @@ private void addEndpointToServiceRecord(
 
   private void updateEndpoint(final ServiceRecord srv, final String endpointName) {
     final String instanceUri = srv.get(INSTANCE_URI_CONFIG);
-    final String[] tokens = instanceUri.split(":");
-    final String hostname = tokens[0];
-    final int port = Integer.parseInt(tokens[1]);
+    IPStackUtils.HostPort hostPort = IPStackUtils.splitHostPort(instanceUri);
+    final String hostname = hostPort.getHostname();
+    final int port = hostPort.getPort();
path: service/src/java/org/apache/hive/service/server/HS2ActivePassiveHARegistry.java
user: login: difin
body: As I see it the problem with this method is that for IPv6 it works only if the hostname portion is enclosed in square brackets (e.g. `[::1]:1000`), while my custom method `IPStackUtils.splitHostPort` works even if it is not enclosed in square brackets. 

While URLs with IPv6 literals are supposed to be enclosed in square brackets, it requires the code that produces the string that is being parsed here to enclose IPv6 in square brackets. Also, what we are parsing here is not a complete URI (URI must contain protocol type such as `http://196.0.0.1:9000` while we parse only `host:port`), I thought it would be more stable to support parsing host/port with and without square brackets.
created_at: 2025-04-04T19:51:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -178,12 +179,13 @@ private static void updateParamsWithZKServerNode(JdbcConnectionParams connParams
     // it must be the server uri added by an older version HS2
     Matcher matcher = kvPattern.matcher(dataStr);
     if ((dataStr != null) && (!matcher.find())) {
-      String[] split = dataStr.split(":");
-      if (split.length != 2) {
+      try {
+        IPStackUtils.HostPort hostPort = IPStackUtils.splitHostPort(dataStr);
+        connParams.setHost(hostPort.getHostname());
+        connParams.setPort(hostPort.getPort());
+      } catch (Exception e) {
         throw new ZooKeeperHiveClientException("Unable to parse HiveServer2 URI from ZooKeeper data: " + dataStr);
       }
-      connParams.setHost(split[0]);
-      connParams.setPort(Integer.parseInt(split[1]));
path: jdbc/src/java/org/apache/hive/jdbc/ZooKeeperHiveClientHelper.java
user: login: difin
body: This method also doesn't work if hostname is IPv6 and not enclosed in square brackets and what we are parsing is not a complete URI..
created_at: 2025-04-04T20:22:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,94 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (1-65535).");
+    }
+    port = Integer.parseInt(portStr);
+
+    // Handle IPv6 addresses enclosed in square brackets (e.g., [IPv6]:port)
+    if (host.startsWith("[") && host.endsWith("]")) {
+      host = host.substring(1, host.length() - 1); // Remove the square brackets
+    }
+
+    // Check if the host is not null or empty
+    if (host == null || host.isEmpty()) {
+      throw new IllegalArgumentException("Host address is null or empty.");
+    }
+
+    return new HostPort(host, port);
+  }
+
+  /**
+   * Validates whether the given string represents a valid port number.
+   * A valid port number is an integer between 0 and 65535 inclusive.
+   *
+   * @param portString The string representing the port number to be validated.
+   * @return {@code true} if the port string is a valid port number, otherwise {@code false}.
+   */
+  public static boolean isValidPort(String portString) {
+    if (portString == null || portString.isEmpty()) {
+      return false;
+    }
+
+    // Regex to check if the port number is between 0 and 65535
+    String regex = "^(0|[1-9][0-9]{0,4})$";
+
+    if (portString.matches(regex)) {
+      int port = Integer.parseInt(portString);
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: difin
body: The method doesn’t parse the port string twice, but there's redundancy in checking with a regex and then parsing the string into an integer. I'll change as you suggested.
created_at: 2025-04-04T20:31:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,94 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (1-65535).");
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: difin
body: We have cases in Hive where we specify port 0, so I think we shouldn't prevent it.

In` MiniCluster.java#82-83`

Was:

```
      m_conf.set("dfs.datanode.address", "0.0.0.0:0");
      m_conf.set("dfs.datanode.http.address", "0.0.0.0:0");
```

I changed it as below in previous IPv6 related PR:

```
      m_conf.set("dfs.datanode.address", IPStackUtils.concatWildcardAddressPort(0));
      m_conf.set("dfs.datanode.http.address", IPStackUtils.concatWildcardAddressPort(0));
```

Besides that, it might be intentional to have OS assign a port dynamically:
**_Port 0 is not used for communication.
It is typically used when a program wants the operating system to automatically assign a free, dynamic port._**

I'll fix the error message to "Port number out of range (0-65535)".
Good catch.
created_at: 2025-04-04T20:40:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -85,7 +85,9 @@ public HiveLockObjectData(String data) {
       lockMode = elem[2];
       queryStr = StringInternUtils.internIfNotNull(elem[3]);
       if (elem.length >= 5) {
-        clientIp = elem[4];
+        String prefix = queryId + ":" + lockTime + ":" + lockMode + ":" + queryStr + ":";
+        // The client IP is the suffix after the 4th colon, this can be IPv6 with colons
+        clientIp = data.substring(data.indexOf(prefix) + prefix.length());
path: ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java
user: login: difin
body: Right, it is always 0.
Refactored this part to have `String[] elem = data.split(":", 5);`, so this won't be needed.
created_at: 2025-04-04T21:13:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -85,7 +85,9 @@ public HiveLockObjectData(String data) {
       lockMode = elem[2];
       queryStr = StringInternUtils.internIfNotNull(elem[3]);
       if (elem.length >= 5) {
-        clientIp = elem[4];
path: ql/src/java/org/apache/hadoop/hive/ql/lockmgr/HiveLockObject.java
user: login: difin
body: Yes, this works. Good catch!
created_at: 2025-04-04T21:14:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: ayushtkn
body: Can use
```
    if (StringUtils.isEmpty(input)) {
```
created_at: 2025-04-06T20:28:52Z
author_association: MEMBER
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: ayushtkn
body: can we just split using `:` ?, so as to save doing the `substring` later, we can have a validation that post split there aren't more than 2 elems?
created_at: 2025-04-06T20:31:03Z
author_association: MEMBER
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (0-65535).");
+    }
+    port = Integer.parseInt(portStr);
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: ayushtkn
body: can change the method to `getPort()` & either return the valid port or throw the exception in that method itself, would save redundant parseInt call
created_at: 2025-04-06T20:32:41Z
author_association: MEMBER
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (0-65535).");
+    }
+    port = Integer.parseInt(portStr);
+
+    // Handle IPv6 addresses enclosed in square brackets (e.g., [IPv6]:port)
+    if (host.startsWith("[") && host.endsWith("]")) {
+      host = host.substring(1, host.length() - 1); // Remove the square brackets
+    }
+
+    // Check if the host is not null or empty
+    if (host == null || host.isEmpty()) {
+      throw new IllegalArgumentException("Host address is null or empty.");
+    }
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: ayushtkn
body: this should be above `` // Handle IPv6 addresses enclosed in square brackets (e.g., [IPv6]:port)``

if host is null, that startsWith will throw `NPE`
created_at: 2025-04-06T20:34:34Z
author_association: MEMBER
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: ayushtkn
body: can we change it to ``getHostAndPort``
created_at: 2025-04-06T20:42:28Z
author_association: MEMBER
diff_hunk: @@ -180,4 +180,72 @@ void testWildcardWhenHostnameIsProvided() {
     String result = IPStackUtils.adaptWildcardAddress("example.com");
     assertEquals("example.com", result);
   }
+
+    // Test cases for splitHostPort method
+
+  @Test
+  void testSplitHostPortWithIPv4() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("192.168.1.1:8080");
+    assertEquals("192.168.1.1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithValidIPv6WithSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("[2001:0db8::1]:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithValidIPv6WithoutSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("2001:0db8::1:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithHostname() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("example.com:80");
+    assertEquals("example.com", result.getHostname());
+    assertEquals(80, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithInvalidPort() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.splitHostPort("192.168.1.1:70000"));
+  }
+
+  @Test
+  void testSplitHostPortWithMissingPort() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.splitHostPort("192.168.1.1"));
+  }
+
+  @Test
+  void testSplitHostPortWithMissingIP() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.splitHostPort(":8080"));
+  }
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: ayushtkn
body: Can you assert the error message as well
created_at: 2025-04-07T06:31:58Z
author_association: MEMBER
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: difin
body: Done
created_at: 2025-04-07T13:29:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: difin
body: The input can be like this: `2001:0db8::1:8080` because IPv6 addresses can contain ":" inside.
host = `2001:0db8::1`
port = `8080`

That's why I made splitting on the last colon..
created_at: 2025-04-07T13:33:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (0-65535).");
+    }
+    port = Integer.parseInt(portStr);
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: difin
body: Done
created_at: 2025-04-07T13:48:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
+
+    String host;
+    int port;
+
+    if (input == null || input.isEmpty()) {
+      throw new IllegalArgumentException("Input string is null or empty");
+    }
+
+    // Check if the input contains a colon, which separates the host and port
+    int colonIndex = input.lastIndexOf(':');
+    if (colonIndex == -1) {
+      throw new IllegalArgumentException("Input does not contain a port.");
+    }
+
+    // Extract the host and port parts
+    host = input.substring(0, colonIndex);
+    String portStr = input.substring(colonIndex + 1);
+
+    // Check if the port is valid
+    if (!isValidPort(portStr)) {
+      throw new IllegalArgumentException("Port number out of range (0-65535).");
+    }
+    port = Integer.parseInt(portStr);
+
+    // Handle IPv6 addresses enclosed in square brackets (e.g., [IPv6]:port)
+    if (host.startsWith("[") && host.endsWith("]")) {
+      host = host.substring(1, host.length() - 1); // Remove the square brackets
+    }
+
+    // Check if the host is not null or empty
+    if (host == null || host.isEmpty()) {
+      throw new IllegalArgumentException("Host address is null or empty.");
+    }
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: difin
body: Fixed
created_at: 2025-04-07T13:51:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,4 +219,91 @@ public static String transformToIPv6(String ipv4, int port) {
       return ipv4;
     }
   }
+
+  /**
+   * Splits a given input string representing a Hostname or an IP address and port into an `HostPort` object.
+   * The input string must be in the format of IPv4/IPv6/[IPv6]/hostname:port.
+   * 
+   * @param input The input string containing the Hostname/IP address and port, in the format 
+   *              "IPv4:port", "[IPv6]:port", "IPv6:port", or "hostname:port".
+   * @return A {@link HostPort} object containing the parsed IP address and port number.
+   * @throws IllegalArgumentException If the input format is invalid, if the host is null or empty,
+   *                                  or if the port number is invalid.
+   */
+  public static HostPort splitHostPort(String input) {
path: common/src/java/org/apache/hive/common/IPStackUtils.java
user: login: difin
body: Done
created_at: 2025-04-07T13:52:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -180,4 +180,72 @@ void testWildcardWhenHostnameIsProvided() {
     String result = IPStackUtils.adaptWildcardAddress("example.com");
     assertEquals("example.com", result);
   }
+
+    // Test cases for splitHostPort method
+
+  @Test
+  void testSplitHostPortWithIPv4() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("192.168.1.1:8080");
+    assertEquals("192.168.1.1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithValidIPv6WithSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("[2001:0db8::1]:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithValidIPv6WithoutSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("2001:0db8::1:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithHostname() {
+    IPStackUtils.HostPort result = IPStackUtils.splitHostPort("example.com:80");
+    assertEquals("example.com", result.getHostname());
+    assertEquals(80, result.getPort());
+  }
+
+  @Test
+  void testSplitHostPortWithInvalidPort() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.splitHostPort("192.168.1.1:70000"));
+  }
+
+  @Test
+  void testSplitHostPortWithMissingPort() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.splitHostPort("192.168.1.1"));
+  }
+
+  @Test
+  void testSplitHostPortWithMissingIP() {
+    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.splitHostPort(":8080"));
+  }
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: difin
body: Done
created_at: 2025-04-07T14:14:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -164,20 +142,68 @@ void testWildcardWhenIPv6IsNotPreferredAndIPv6WildcardProvided() {
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv4AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("192.168.1.1");
-    assertEquals("192.168.1.1", result);
+  void testAdaptWildcardAddress() {
+    assertEquals("192.168.1.1", IPStackUtils.adaptWildcardAddress("192.168.1.1"));
+    assertEquals("2001:db8::1", IPStackUtils.adaptWildcardAddress("2001:db8::1"));
+    assertEquals("example.com", IPStackUtils.adaptWildcardAddress("example.com"));
+  }
+
+    // Test cases for splitHostPort method
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: ayushtkn
body: getHostAndPort
created_at: 2025-04-08T02:15:14Z
author_association: MEMBER
diff_hunk: @@ -164,20 +142,68 @@ void testWildcardWhenIPv6IsNotPreferredAndIPv6WildcardProvided() {
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv4AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("192.168.1.1");
-    assertEquals("192.168.1.1", result);
+  void testAdaptWildcardAddress() {
+    assertEquals("192.168.1.1", IPStackUtils.adaptWildcardAddress("192.168.1.1"));
+    assertEquals("2001:db8::1", IPStackUtils.adaptWildcardAddress("2001:db8::1"));
+    assertEquals("example.com", IPStackUtils.adaptWildcardAddress("example.com"));
+  }
+
+    // Test cases for splitHostPort method
+
+  @Test
+  void testGetHostAndPortWithIPv4() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("192.168.1.1:8080");
+    assertEquals("192.168.1.1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("[2001:0db8::1]:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithoutSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("2001:0db8::1:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithHostname() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("example.com:80");
+    assertEquals("example.com", result.getHostname());
+    assertEquals(80, result.getPort());
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv6AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("2001:db8::1");
-    assertEquals("2001:db8::1", result);
+  void testGetHostPortWithInvalidAndPort() {
+    assertEquals("Port number out of range (0-65535).",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1:70000")).getMessage());
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: ayushtkn
body: assertThrows can directly assert the message, We don't need assertEquals I believe
```
    assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1:70000"),
        "Port number out of range (0-65535).");
```
created_at: 2025-04-08T02:17:27Z
author_association: MEMBER
diff_hunk: @@ -164,20 +142,68 @@ void testWildcardWhenIPv6IsNotPreferredAndIPv6WildcardProvided() {
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv4AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("192.168.1.1");
-    assertEquals("192.168.1.1", result);
+  void testAdaptWildcardAddress() {
+    assertEquals("192.168.1.1", IPStackUtils.adaptWildcardAddress("192.168.1.1"));
+    assertEquals("2001:db8::1", IPStackUtils.adaptWildcardAddress("2001:db8::1"));
+    assertEquals("example.com", IPStackUtils.adaptWildcardAddress("example.com"));
+  }
+
+    // Test cases for splitHostPort method
+
+  @Test
+  void testGetHostAndPortWithIPv4() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("192.168.1.1:8080");
+    assertEquals("192.168.1.1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("[2001:0db8::1]:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithoutSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("2001:0db8::1:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithHostname() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("example.com:80");
+    assertEquals("example.com", result.getHostname());
+    assertEquals(80, result.getPort());
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv6AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("2001:db8::1");
-    assertEquals("2001:db8::1", result);
+  void testGetHostPortWithInvalidAndPort() {
+    assertEquals("Port number out of range (0-65535).",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1:70000")).getMessage());
+    assertEquals("Input does not contain a port.",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1")).getMessage());
+    assertEquals("Host address is null or empty.",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort(":8080")).getMessage());
+  }
+
+  // Test cases for isValidPort method
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: ayushtkn
body: getPort
created_at: 2025-04-08T02:17:36Z
author_association: MEMBER
diff_hunk: @@ -164,20 +142,68 @@ void testWildcardWhenIPv6IsNotPreferredAndIPv6WildcardProvided() {
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv4AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("192.168.1.1");
-    assertEquals("192.168.1.1", result);
+  void testAdaptWildcardAddress() {
+    assertEquals("192.168.1.1", IPStackUtils.adaptWildcardAddress("192.168.1.1"));
+    assertEquals("2001:db8::1", IPStackUtils.adaptWildcardAddress("2001:db8::1"));
+    assertEquals("example.com", IPStackUtils.adaptWildcardAddress("example.com"));
+  }
+
+    // Test cases for splitHostPort method
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: difin
body: Done
created_at: 2025-04-08T21:09:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -164,20 +142,68 @@ void testWildcardWhenIPv6IsNotPreferredAndIPv6WildcardProvided() {
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv4AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("192.168.1.1");
-    assertEquals("192.168.1.1", result);
+  void testAdaptWildcardAddress() {
+    assertEquals("192.168.1.1", IPStackUtils.adaptWildcardAddress("192.168.1.1"));
+    assertEquals("2001:db8::1", IPStackUtils.adaptWildcardAddress("2001:db8::1"));
+    assertEquals("example.com", IPStackUtils.adaptWildcardAddress("example.com"));
+  }
+
+    // Test cases for splitHostPort method
+
+  @Test
+  void testGetHostAndPortWithIPv4() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("192.168.1.1:8080");
+    assertEquals("192.168.1.1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("[2001:0db8::1]:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithoutSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("2001:0db8::1:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithHostname() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("example.com:80");
+    assertEquals("example.com", result.getHostname());
+    assertEquals(80, result.getPort());
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv6AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("2001:db8::1");
-    assertEquals("2001:db8::1", result);
+  void testGetHostPortWithInvalidAndPort() {
+    assertEquals("Port number out of range (0-65535).",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1:70000")).getMessage());
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: difin
body: Done
created_at: 2025-04-08T21:14:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -164,20 +142,68 @@ void testWildcardWhenIPv6IsNotPreferredAndIPv6WildcardProvided() {
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv4AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("192.168.1.1");
-    assertEquals("192.168.1.1", result);
+  void testAdaptWildcardAddress() {
+    assertEquals("192.168.1.1", IPStackUtils.adaptWildcardAddress("192.168.1.1"));
+    assertEquals("2001:db8::1", IPStackUtils.adaptWildcardAddress("2001:db8::1"));
+    assertEquals("example.com", IPStackUtils.adaptWildcardAddress("example.com"));
+  }
+
+    // Test cases for splitHostPort method
+
+  @Test
+  void testGetHostAndPortWithIPv4() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("192.168.1.1:8080");
+    assertEquals("192.168.1.1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("[2001:0db8::1]:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithValidIPv6WithoutSquaredBrackets() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("2001:0db8::1:8080");
+    assertEquals("2001:0db8::1", result.getHostname());
+    assertEquals(8080, result.getPort());
+  }
+
+  @Test
+  void testGetHostAndPortWithHostname() {
+    IPStackUtils.HostPort result = IPStackUtils.getHostAndPort("example.com:80");
+    assertEquals("example.com", result.getHostname());
+    assertEquals(80, result.getPort());
   }
 
   @Test
-  void testWildcardWhenNonWildcardIPv6AddressProvided() {
-    String result = IPStackUtils.adaptWildcardAddress("2001:db8::1");
-    assertEquals("2001:db8::1", result);
+  void testGetHostPortWithInvalidAndPort() {
+    assertEquals("Port number out of range (0-65535).",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1:70000")).getMessage());
+    assertEquals("Input does not contain a port.",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort("192.168.1.1")).getMessage());
+    assertEquals("Host address is null or empty.",
+        assertThrows(IllegalArgumentException.class, () -> IPStackUtils.getHostAndPort(":8080")).getMessage());
+  }
+
+  // Test cases for isValidPort method
path: common/src/test/org/apache/hive/common/IPStackUtilsTest.java
user: login: difin
body: Fixed
created_at: 2025-04-08T21:17:21Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-08T22:32:56Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=apache_hive&pullRequest=5729) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=apache_hive&pullRequest=5729&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=apache_hive&pullRequest=5729&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_hive&pullRequest=5729&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=apache_hive&pullRequest=5729&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=apache_hive&pullRequest=5729&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=apache_hive&pullRequest=5729)


author_association: NONE