Bug #84586 getConnection will failed if ConnectionAttributes is large than 255
Submitted: 20 Jan 2017 13:40 Modified: 24 Jan 2017 10:21
Reporter: Feizhi Cai Email Updates:
Status: Verified Impact on me:
None 
Category:Connector / J Severity:S3 (Non-critical)
Version:5.1.30, 5.1.40 OS:Any
Assigned to: CPU Architecture:Any
Tags: ConnectionAttributes

[20 Jan 2017 13:40] Feizhi Cai
Description:
if user-defined ConnectionAttributes length is large than 255(actually less than this length, as mysql-connector-j defined its ConnectionAttributes ), connector will failed to getConnection

How to repeat:
    String url = String.format("jdbc:mysql://%s/%s?connectionAttributes=", proxyAddr, databaseName);
    String key = "k1";
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < 255; ++i) {
      builder.append("v");
    }
    String value = builder.toString();
    url += key + ":" + value;

    Connection connection = null;
    try {
      connection = DriverManager.getConnection(url, username, password) ;
    } catch (Exception e) {
      System.out.println("oooooooops");
    }

Suggested fix:
the code in connector/J MysqlIo.java sendConnectionAttributes function:

        String atts = conn.getConnectionAttributes();

        Buffer lb = new Buffer(100);
        try {

            Properties props = getConnectionAttributesAsProperties(atts);

            for (Object key : props.keySet()) {
                lb.writeLenString((String) key, enc, conn.getServerCharset(), null, conn.parserKnowsUnicode(), conn);
                lb.writeLenString(props.getProperty((String) key), enc, conn.getServerCharset(), null, conn.parserKnowsUnicode(), conn);
            }

        } catch (UnsupportedEncodingException e) {

        }

        buf.writeByte((byte) (lb.getPosition() - 4));
        buf.writeBytesNoNull(lb.getByteBuffer(), 4, lb.getBufLength() - 4);

if (lb.getPosition() - 4) is larger than a byte(255), the buf length written in the first byte is incorrect
[23 Jan 2017 12:38] Chiranjeevi Battula
Hello Feizhi Cai,

Thank you for the bug report.
I tried to reproduce the issue at my end using MySQL Connector / J 5.1.40 and MySQL 5.7.17 but not seeing any issues in ConnectionAttributes is large than 255.
Could you please provide us repeatable test case (steps, sample code, full stack trace etc. - please make it as private if you prefer) to confirm this issue at our end?

Thanks,
Chiranjeevi.
[23 Jan 2017 12:53] Feizhi Cai
As shown above, the connection attributes can be set by user.
if a user set the connection attributes (it happened in my project), the whole length of connection attributes may be larger than 255.

You can use this code, to generate a connection attribute large than 255:

    String url = String.format("jdbc:mysql://%s/%s?connectionAttributes=", addr, databaseName);
    String key = "key";
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < 255; ++i) {
      builder.append("v");
    }
    String value = builder.toString();
    url += key + ":" + value;
    connection = DriverManager.getConnection(url, username, password) ;

You need to specify addr,databaseName,username,password yourself.
[23 Jan 2017 13:00] Chiranjeevi Battula
Hello Feizhi Cai,

Thank you for the feedback.
I could not repeat the issue at my end using your test case with MySQL Connector / J 5.1.40 and MySQL 5.7.17 version.

Thanks,
Chiranjeevi.
[23 Jan 2017 13:46] Feizhi Cai
It seems mysql 5.7 will no disconnect while the connection attribute is not correct(but in my db(Compatible with the mysql protocol), this will cause a SQLException).

So I wrote another code to show this:

    String urlBase = String.format("jdbc:mysql://%s/%s?connectionAttributes=", proxyAddr, databaseName);

    String key = "key";
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < 255; ++i) {
      builder.append("v");
    }
    String value = builder.toString();
    String shortUrl = urlBase + key + ":" + "value";
    String longUrl = urlBase + key + ":" + value;

    Connection connection = DriverManager.getConnection(shortUrl, username, password) ;
    Statement stmt = connection.createStatement();
    ResultSet rs = stmt.executeQuery("select * from  performance_schema.session_connect_attrs;");
    boolean foundShortValue = false;
    while (rs.next()) {
      if (rs.getString("ATTR_NAME").equals(key)) {
        foundShortValue = true;
      }
    }
    rs.close();
    connection.close();

    boolean foundLongValue = false;
    connection = DriverManager.getConnection(longUrl, username, password) ;
    stmt = connection.createStatement();
    rs = stmt.executeQuery("select * from  performance_schema.session_connect_attrs;");
    while (rs.next()) {
      if (rs.getString("ATTR_NAME").equals(key)) {
        foundLongValue = true;
      }
    }
    rs.close();
    connection.close();

    System.out.println("foundShortValue = " + foundShortValue + ", foundLongValue = " + foundLongValue);

The output will be:
foundShortValue = true, foundLongValue = false

So if the connection attribute is large than 255, the user defined attribute will miss;
[24 Jan 2017 10:21] Chiranjeevi Battula
Hello Feizhi Cai,

Thank you for the feedback and test case.
Verified this behavior on MySQL Connector / J 5.1.40.

Thanks,
Chiranjeevi.