Uploaded image for project: 'MariaDB Connector/J'
  1. MariaDB Connector/J
  2. CONJ-693

Connection leak when executing query with invalid parameters

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.4.0
    • Fix Version/s: N/A
    • Component/s: protocol
    • Labels:
      None

      Description

      Happens when running in sequential HA mode with Client Prepared Statement in a transaction.

      Create prepared statement and bind parameter to non-serializable object:

      try(PreparedStatement statement = connection.prepareStatement("SELECT * FROM test WHERE column = ?"))
      {
          statement.setObject(1, new Object());
          statement.execute();
      }
      

      Executing such query and writing parameters into the OutputStream (i.e. when calling "ComQuery.sendSubCmd"), results in "java.io.NotSerializableException: java.lang.Object".

      Stack trace:

      java.io.NotSerializableException: java.lang.Object
      	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
      	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
      	at org.mariadb.jdbc.internal.com.send.parameters.SerializableParameter.writeObjectToBytes(SerializableParameter.java:91)
      	at org.mariadb.jdbc.internal.com.send.parameters.SerializableParameter.writeTo(SerializableParameter.java:80)
      	at org.mariadb.jdbc.internal.com.send.ComQuery.sendSubCmd(ComQuery.java:85)
      	at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:285)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at org.mariadb.jdbc.internal.failover.AbstractMastersListener.invoke(AbstractMastersListener.java:398)
      	at org.mariadb.jdbc.internal.failover.FailoverProxy.executeInvocation(FailoverProxy.java:278)
      	at org.mariadb.jdbc.internal.failover.FailoverProxy.invoke(FailoverProxy.java:270)
      	at com.sun.proxy.$Proxy8.executeQuery(Unknown Source)
      	at org.mariadb.jdbc.ClientSidePreparedStatement.executeInternal(ClientSidePreparedStatement.java:221)
      	at org.mariadb.jdbc.ClientSidePreparedStatement.execute(ClientSidePreparedStatement.java:157)
      	at org.mariadb.jdbc.ClientSidePreparedStatement.executeUpdate(ClientSidePreparedStatement.java:192)
      

      What is happening:

      1. "AbstractQueryProtocol.handleIoException" method will mark the protocol as not connected, via: "connected = false;"
      2. FailoverProxy.executeInvocation catches the exception and enters the block:

                  if (hasToHandleFailover(queryException)) {
                    return handleFailOver(queryException, method, args, protocol);
                  }
        

      3. MastersFailoverLustener.primaryFail will reconnect with a new protocol, but because the protocol returns false on "currentProtocol.isConnected()", existing protocol is not closed.

          @Override
          public HandleErrorResult primaryFail(Method method, Object[] args, boolean killCmd) {
            boolean alreadyClosed = !currentProtocol.isConnected();
            boolean inTransaction = currentProtocol != null && currentProtocol.inTransaction();
         
            if (currentProtocol.isConnected()) {
              currentProtocol.close();
            }
         
            try {
              reconnectFailedConnection(new SearchFilter(true, false));
        

      4. During reconnection in "reconnectFailedConnection" method, "MastersFailoverListener.foundActiveMaster" method is called, which override current protocol's reference, without closing existing one, as "currentProtocol.isClosed()" returns true

              if (currentProtocol != null && !currentProtocol.isClosed()) {
                currentProtocol.close();
              }
              currentProtocol = protocol;
        

      Results in hanging open connection to database every time you run into above scenario. Calling "close" on the Connection, does not close the old protocol.

      I would expect that "AbstractQueryProtocol.handleIoException" method to not assume that IOExceptions is due to connection being broken and actually close the protocol and not just flag it as "closed".

        Attachments

          Activity

            People

            Assignee:
            diego dupin Diego Dupin
            Reporter:
            maciej.zieniuk Maciej Zieniuk
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:

                Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.