Bug #32216 parseURL method in com.mysql.jdbc.Driver doesn't work properly
Submitted: 9 Nov 2007 10:03 Modified: 16 Sep 2009 16:03
Reporter: Krystian Nowak Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S3 (Non-critical)
Version:5.1.5 OS:Any
Assigned to: CPU Architecture:Any
Tags: parseURL host port Driver parse

[9 Nov 2007 10:03] Krystian Nowak
Description:
The "parseURL" method in class "com.mysql.jdbc.Driver" doesn't work properly.
When having an URL like given below:
jdbc:mysql://www.mysql.com:12345/my_database
then when calling "driver.parseURL()" and getting property PORT_PROPERTY_KEY, null is received, but when getting HOST_PROPERTY_KEY propery, "www.mysql.com:12345" is received.

How to repeat:
Use the following unit test:

package com.mysql.jdbc;

import java.sql.SQLException;
import java.util.Properties;

import junit.framework.TestCase;

/**
 * @author Krystian Nowak
 */
public class DriverTest
    extends TestCase
{
    private Driver driver;

    public DriverTest()
        throws SQLException
    {
        driver = new Driver();
    }

    public void testWithPort()
        throws SQLException
    {
        check("www.mysql.com", "12345", "my_database");
    }

    public void testWithoutPort()
        throws SQLException
    {
        check("www.mysql.com", null, "my_database");
    }

    private void check(String host, String port, String dbname)
        throws SQLException
    {
        StringBuffer url = new StringBuffer("jdbc:mysql://");
        url.append(host);

        if (port != null) {
            url.append(':');
            url.append(port);
        }

        url.append('/');
        url.append(dbname);

        Properties result = driver.parseURL(url.toString(), new Properties());

        assertEquals("hostname not equal", host, result
                .getProperty(Driver.HOST_PROPERTY_KEY));
        assertEquals("port not equal", port, result
                .getProperty(Driver.PORT_PROPERTY_KEY));
        assertEquals("dbname not equal", dbname, result
                .getProperty(Driver.DBNAME_PROPERTY_KEY));
    }

}

Suggested fix:
Change the implementation of a method having the following signature:

public Properties parseURL(String url, Properties defaults)
			throws java.sql.SQLException

defined in com.mysql.jdbc.NonRegisteringDriver by using a method defined in the same class with a signature given below:

protected static String[] parseHostPortPair(String hostPortPair)
			throws SQLException

and then by properly setting returned properties under keys named HOST_PROPERTY_KEY and PORT_PROPERTY_KEY
[9 Nov 2007 19:29] Mark Matthews
(note that the behavior is legacy, and internal to the driver).

What exactly are you needing the output of parseURL() to do, since the method itself, and the values that end up getting parsed out are not part of the JDBC API. 

Without knowing what someone who's depending on some internal implementation expects "externally", we can't propose a fix that would work for you, since there is no standard (and currently the driver depends on the behavior that is there, it's not as simple as just "fixing" parseURL() to operate the way you're asking).
[9 Nov 2007 22:40] Krystian Nowak
com.mysql.jdbc.Driver's parseURL method is public. I've just tried to use this to parse MySQL JDBC URL used in my infrastructure (from Ant) and I've expected that parsing is already done in MySQL JDBC driver. But I was surprised to see what is assigned to various keys in Properties after parsing. Now I wrap it in my own util to override host and port fields parsing. That is all. It's not the issue to be compatible or not with implemented SQL Driver interface, but rather the notion of clean implementation and trust what's inside in non-public methods. Personally, I can handle by using wrapper to hide this bug or even to write my own JDBC URL parser, but if the connector is open-source, then why we all should re-invent the wheel all the time?

Of course if help in the implementation of a fix is necessary I can take a look at driver's internals.

Regards,
Krystian
[9 Nov 2007 22:45] Mark Matthews
Don't take offense, we just wanted to know how you're using it so we can fix it in a way that suits what you're doing, rather than waste effort in delivering something you can't use.

Just realize it's not as simple a fix as making it output PORT properties consistently, since that affects how the driver works internally.
[9 Nov 2007 22:52] Krystian Nowak
No offense, of course.

This usage might not be most common, but still can be used by some.

Of course I know that many things depend on the current driver's implementation, but it is better to have this issue documented, even on a low priority (it's not critical and - as I estimate - not many users use the driver in this way), than to forget about it.

Regards,
Krystian
[14 Aug 2009 19:32] Mark Matthews
Fixed for 5.1.9.

The driver will now always fill in the "PORT" (using 3306 if not specified) property, and the "HOST" property (using "localhost" if not specified) when parseURL() is called. The driver also parses a list of hosts into HOST.n and PORT.n properties as well as adding a property "NUM_HOSTS" for the number of hosts it has found. If a list of hosts is passed to the driver, "HOST" and "PORT" will be set to the values given by "HOST.1" and "PORT.1" respectively. This change has centralized and cleaned up a large swath of code used to generate lists of hosts, both for load-balanced and fault tolerant connections and their tests.
[16 Sep 2009 16:03] Tony Bedford
An entry has been added to the 5.1.9 changelog:

The parseURL method in class com.mysql.jdbc.Driver did not work as expected. When given a URL such as “jdbc:mysql://www.mysql.com:12345/my_database” to parse, the property PORT_PROPERTY_KEY was found to be null and the HOST_PROPERTY_KEY property was found to be “www.mysql.com:12345”.

Note

Connector/J has been fixed so that it will now always fill in the PORT property (using 3306 if not specified), and the HOST property (using localhost if not specified) when parseURL() is called. The driver also parses a list of hosts into HOST.n and PORT.n properties as well as adding a property NUM_HOSTS for the number of hosts it has found. If a list of hosts is passed to the driver, HOST and PORT will be set to the values given by HOST.1 and PORT.1 respectively. This change has centralized and cleaned up a large section of code used to generate lists of hosts, both for load-balanced and fault tolerant connections and their tests.