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

QueryRunner的update方法执行/**/时会报错

Details

    • Bug
    • Status: Closed (View Workflow)
    • Major
    • Resolution: Fixed
    • 2.4.0
    • 2.6.1, 3.0.3
    • metadata
    • None
    • jdk1.8
      mariadb connector 2.4.1
      mysql 5.1.71 或者 mariadb 10.3.12

    Description

      用mysql的connector/j 不会报错
      用mariadb的connector/j 会报错
      [ERROR] 2019-05-30 09:36:02,452 com.lenovo.leapedge.utils.UpdateDatabasesByScript - sql执行错误
      java.sql.SQLException: Parameter metadata not available for these statement Query: /**/ Parameters: []
      at org.apache.commons.dbutils.AbstractQueryRunner.rethrow(AbstractQueryRunner.java:392)
      at org.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:491)
      at org.apache.commons.dbutils.QueryRunner.update(QueryRunner.java:377)
      at com.lenovo.leapedge.utils.UpdateDatabasesByScript.runTableScripts(UpdateDatabasesByScript.java:387)
      at com.lenovo.leapedge.utils.UpdateDatabasesByScript.doUpdate(UpdateDatabasesByScript.java:219)
      at com.lenovo.leapedge.EdgeMqttRunner.initDatabases(EdgeMqttRunner.java:93)
      at com.lenovo.leapedge.EdgeMqttRunner.run(EdgeMqttRunner.java:63)
      at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797)
      at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:781)
      at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
      at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255)
      at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243)
      at com.lenovo.leapedge.Application.main(Application.java:24)

      Attachments

        Activity

          diego dupin Diego Dupin added a comment -

          Could you please elaborate on the issue ?
          query was "/**/" ? If so error message "Parameter metadata not available for these statement" seems adequate, because server cannot return metadata for this query.

          diego dupin Diego Dupin added a comment - Could you please elaborate on the issue ? query was "/**/" ? If so error message "Parameter metadata not available for these statement" seems adequate, because server cannot return metadata for this query.
          diego dupin Diego Dupin added a comment -

          Closing since no answer

          diego dupin Diego Dupin added a comment - Closing since no answer
          vasvir Vassilis Virvilis added a comment - - edited

          Hi,

          I can verify that and answer questions or try builds if required. I can probably try patches also.

          The issue is also discussed in https://issues.apache.org/jira/browse/DBUTILS-117

          How the problem manifests itself: Apache Commons DbUtils are crashing when they try to execute a prepared statement with no parameters. For me it was just a "LOAD DATA INFILE '/tmp/data.txt' INTO TABLE mytable";

          The problem lies in (I have version 2.6.0 of the mariadb java connector) in org.mariadb.jdbc.MariaDbParameterMetaData around line 77. When the AbstractQueryRunner:334 (of DbUtils) calls fillStatement() it tries to check the numbers of parameters.

          DbUtils have some defensive code there. They check if getParameterMetaData() throws SQLFeatureNotSupportedException or returns null. MariaDB does not throw SQLFeatureNotSupportedException and does not return null. The jdbc implementations is considered okish and DbUtils tries to getParameterCount() which calls MariaDbParameterMetaData:77

          Now the MariaDB connector calls checkAvailable() if parametersInformation == null then throws

          {{ throw new SQLException("Parameter metadata not available for these statement", "S1C00");}}

          What it has to be done (according to my opinion)

          getParameterCount() should return 0 and do not throw exception.

          I can try cook a patch if you agree with this behavior.

          I am sure however that there is more to this than my naive approach but MySQL implementation seems to protect it. Not quite sure though about that. Probably the jdbc standard will have an opinion of its own on this.

          Please consider altering this behaviour though. It hurts portability from MySQL.

          Workaround

          Instantiate the QueryRunner with a boolean set to true which sets the internal variable pmdKnownBroken in order to handle substandard jdbc drivers.

          vasvir Vassilis Virvilis added a comment - - edited Hi, I can verify that and answer questions or try builds if required. I can probably try patches also. The issue is also discussed in https://issues.apache.org/jira/browse/DBUTILS-117 How the problem manifests itself : Apache Commons DbUtils are crashing when they try to execute a prepared statement with no parameters. For me it was just a "LOAD DATA INFILE '/tmp/data.txt' INTO TABLE mytable"; The problem lies in (I have version 2.6.0 of the mariadb java connector) in org.mariadb.jdbc.MariaDbParameterMetaData around line 77. When the AbstractQueryRunner:334 (of DbUtils) calls fillStatement() it tries to check the numbers of parameters. DbUtils have some defensive code there. They check if getParameterMetaData() throws SQLFeatureNotSupportedException or returns null. MariaDB does not throw SQLFeatureNotSupportedException and does not return null. The jdbc implementations is considered okish and DbUtils tries to getParameterCount() which calls MariaDbParameterMetaData:77 Now the MariaDB connector calls checkAvailable() if parametersInformation == null then throws {{ throw new SQLException("Parameter metadata not available for these statement", "S1C00");}} What it has to be done (according to my opinion) getParameterCount() should return 0 and do not throw exception. I can try cook a patch if you agree with this behavior. I am sure however that there is more to this than my naive approach but MySQL implementation seems to protect it. Not quite sure though about that. Probably the jdbc standard will have an opinion of its own on this. Please consider altering this behaviour though. It hurts portability from MySQL. Workaround Instantiate the QueryRunner with a boolean set to true which sets the internal variable pmdKnownBroken in order to handle substandard jdbc drivers.
          diego dupin Diego Dupin added a comment -

          For client (default) prepare statement, metadata are done by executing a "PREPARE" command and using the resulting metadata.
          Problem is that a few commands, like LOAD DATA cmds.

          Driver return a metadata object without any information, so that will throw an exception for all methods.
          Acording to JDBC : https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/PreparedStatement.html#getMetaData()

          Returns: the description of a ResultSet object's columns or null if the driver cannot return a ResultSetMetaData object

          Driver has to return null in this specific case.

          diego dupin Diego Dupin added a comment - For client (default) prepare statement, metadata are done by executing a "PREPARE" command and using the resulting metadata. Problem is that a few commands, like LOAD DATA cmds. Driver return a metadata object without any information, so that will throw an exception for all methods. Acording to JDBC : https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/PreparedStatement.html#getMetaData( ) Returns: the description of a ResultSet object's columns or null if the driver cannot return a ResultSetMetaData object Driver has to return null in this specific case.

          Hi thanks for answering and for the link.

          I think there is a misunderstanding though.

          You are speaking about ResultSetMetaData object while my issue is in the implementation of ParameterMetaData (MariaDbParameterMetaData).

          Here is the code from Apache Commons DbUtils AbstractQueryRunner.java It can be found here: https://github.com/apache/commons-dbutils/blob/master/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java#L278

                  // check the parameter count, if we can
                  ParameterMetaData pmd = null;
                  if (!pmdKnownBroken) {
                      try {
                          pmd = stmt.getParameterMetaData();
                          if (pmd == null) { // can be returned by implementations that don't support the method
                              pmdKnownBroken = true;
                          } else {
                              int stmtCount = pmd.getParameterCount();     // <----------------- IT CRASHSES HERE ******** 
                              int paramsCount = params == null ? 0 : params.length;
                  
                              if (stmtCount != paramsCount) {
                                  throw new SQLException("Wrong number of parameters: expected "
                                          + stmtCount + ", was given " + paramsCount);
                              }
                          }
                      } catch (SQLFeatureNotSupportedException ex) {
                          pmdKnownBroken = true;                
                      }
                      // TODO see DBUTILS-117: would it make sense to catch any other SQLEx types here?
                  }
          

          https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/ParameterMetaData.html#getParameterCount() does not indicate that it should throw an exception if there are no parameters. If there are no parameters the number of parameters returned should be 0 IMHO (implied not explicitely stated).

          In the same vain the query of the original reporter '/**/' is a valid SQL query with zero paramters. Why it should throw an exception when we ask the parameter count?

          This works in MySQL and apparently in other JDBC drivers so I genuinely believe it is an implementation bug in MariaDB JDBC connector

          Here is the patch I propose:

          diff --git a/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java
          index e663eb85..73b53d2b 100644
          --- a/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java
          +++ b/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java
          @@ -75,8 +75,7 @@ public class MariaDbParameterMetaData implements ParameterMetaData {
           
             @Override
             public int getParameterCount() throws SQLException {
          -    checkAvailable();
          -    return parametersInformation.length;
          +    return (this.parametersInformation != null) ? parametersInformation.length : 0;
             }
           
             private ColumnDefinition getParameterInformation(int param) throws SQLException {
          

          I am willing to formally submit a patch and create a test case if you agree with it.

          Thanks in advance

          vasvir Vassilis Virvilis added a comment - Hi thanks for answering and for the link. I think there is a misunderstanding though. You are speaking about ResultSetMetaData object while my issue is in the implementation of ParameterMetaData (MariaDbParameterMetaData). Here is the code from Apache Commons DbUtils AbstractQueryRunner.java It can be found here: https://github.com/apache/commons-dbutils/blob/master/src/main/java/org/apache/commons/dbutils/AbstractQueryRunner.java#L278 // check the parameter count, if we can ParameterMetaData pmd = null ; if (!pmdKnownBroken) { try { pmd = stmt.getParameterMetaData(); if (pmd == null ) { // can be returned by implementations that don't support the method pmdKnownBroken = true ; } else { int stmtCount = pmd.getParameterCount(); // <----------------- IT CRASHSES HERE ******** int paramsCount = params == null ? 0 : params.length; if (stmtCount != paramsCount) { throw new SQLException( "Wrong number of parameters: expected " + stmtCount + ", was given " + paramsCount); } } } catch (SQLFeatureNotSupportedException ex) { pmdKnownBroken = true ; } // TODO see DBUTILS-117: would it make sense to catch any other SQLEx types here? } https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/ParameterMetaData.html#getParameterCount( ) does not indicate that it should throw an exception if there are no parameters. If there are no parameters the number of parameters returned should be 0 IMHO (implied not explicitely stated). In the same vain the query of the original reporter '/**/' is a valid SQL query with zero paramters. Why it should throw an exception when we ask the parameter count? This works in MySQL and apparently in other JDBC drivers so I genuinely believe it is an implementation bug in MariaDB JDBC connector Here is the patch I propose: diff --git a/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java b/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java index e663eb85..73b53d2b 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbParameterMetaData.java @@ - 75 , 8 + 75 , 7 @@ public class MariaDbParameterMetaData implements ParameterMetaData { @Override public int getParameterCount() throws SQLException { - checkAvailable(); - return parametersInformation.length; + return ( this .parametersInformation != null ) ? parametersInformation.length : 0 ; } private ColumnDefinition getParameterInformation( int param) throws SQLException { I am willing to formally submit a patch and create a test case if you agree with it. Thanks in advance
          diego dupin Diego Dupin added a comment -

          allright, i've added commit https://github.com/mariadb-corporation/mariadb-connector-j/commit/12af84fa31c2fc47280877b18a083ebe1e7be0db that at least permits parameterCount() for parameterMetadata (that's the only known data when query cannot be prepared).

          You can test result using snapshot version:

           
          <repositories>
              <repository>
                  <id>sonatype-nexus-snapshots</id>
                  <name>Sonatype Nexus Snapshots</name>
                  <url>https://oss.sonatype.org/content/repositories/snapshots</url>
              </repository>
          </repositories>
           
          <dependencies>
              <dependency>
                  <groupId>org.mariadb.jdbc</groupId>
                  <artifactId>mariadb-java-client</artifactId>
                  <version>2.6.1-SNAPSHOT</version>
              </dependency>
          </dependencies>
          

          could you confirm that solve this issue ?

          diego dupin Diego Dupin added a comment - allright, i've added commit https://github.com/mariadb-corporation/mariadb-connector-j/commit/12af84fa31c2fc47280877b18a083ebe1e7be0db that at least permits parameterCount() for parameterMetadata (that's the only known data when query cannot be prepared). You can test result using snapshot version:   <repositories> <repository> <id>sonatype-nexus-snapshots</id> <name>Sonatype Nexus Snapshots</name> <url>https: //oss.sonatype.org/content/repositories/snapshots</url> </repository> </repositories>   <dependencies> <dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <version> 2.6 . 1 -SNAPSHOT</version> </dependency> </dependencies> could you confirm that solve this issue ?

          Diego,

          I confirm that it works.

          I also saw that you added a test case too. That will prevent it from breaking in the feature. Super cool !!!

          Thanks a lot.

          I really appreciate it.

          vasvir Vassilis Virvilis added a comment - Diego, I confirm that it works. I also saw that you added a test case too. That will prevent it from breaking in the feature. Super cool !!! Thanks a lot. I really appreciate it.

          People

            diego dupin Diego Dupin
            13121723599@163.com Xu Shilin
            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.