Repository: pinpoint-apm/pinpoint
Issue: Add support for Mariadb java client 1.6.x and 2.x
Labels: enhancement
module:plugin

#### Description
Mariadb 1.6.x and 2.x are available and will need support as class names for callable and prepared statements are changed.


Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBPlugin.java b/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBPlugin.java
index fb19c2427606..7abd9072f949 100644
--- a/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBPlugin.java
+++ b/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBPlugin.java
@@ -195,6 +195,9 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
 
         transformTemplate.transform("org.mariadb.jdbc.MariaDbServerPreparedStatement", transformer);
         transformTemplate.transform("org.mariadb.jdbc.MariaDbClientPreparedStatement", transformer);
+        // 1.6.x
+        transformTemplate.transform("org.mariadb.jdbc.MariaDbPreparedStatementServer", transformer);
+        transformTemplate.transform("org.mariadb.jdbc.MariaDbPreparedStatementClient", transformer);
 
     }
 
@@ -229,7 +232,8 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
         transformTemplate.transform("org.mariadb.jdbc.AbstractMariaDbPrepareStatement", transformer);
         // Class renamed in 1.5.6 - https://github.com/MariaDB/mariadb-connector-j/commit/16c8313960cf4fbc6b2b83136504d1ba9e662919
         transformTemplate.transform("org.mariadb.jdbc.AbstractPrepareStatement", transformer);
-
+        // 1.6.x
+        transformTemplate.transform("org.mariadb.jdbc.BasePrepareStatement", transformer);
     }
 
     private void addStatementTransformer() {
@@ -295,6 +299,9 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
 
         transformTemplate.transform("org.mariadb.jdbc.AbstractCallableProcedureStatement", transformer);
         transformTemplate.transform("org.mariadb.jdbc.AbstractCallableFunctionStatement", transformer);
+        // 1.6.x
+        transformTemplate.transform("org.mariadb.jdbc.CallableProcedureStatement", transformer);
+        transformTemplate.transform("org.mariadb.jdbc.CallableFunctionStatement", transformer);
     }
 
     private void add_1_3_x_CallableStatementTransformer(final MariaDBConfig config) {


Test patch:
diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java
index c1a855fc2491..a95a6bf301ea 100644
--- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java
+++ b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 NAVER Corp.
+ *
+ * Licensed 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 com.navercorp.pinpoint.plugin.jdbc.mariadb;
 
 import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*;
@@ -14,6 +30,9 @@
 import com.navercorp.pinpoint.test.plugin.JvmVersion;
 import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite;
 
+/**
+ * @author HyunGil Jeong
+ */
 @RunWith(PinpointPluginTestSuite.class)
 @JvmVersion(7)
 @Dependency({"org.mariadb.jdbc:mariadb-java-client:[1.3.0,1.3.max]", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2"})
diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java
index 5e241d3d0b1d..3c8fcfea2270 100644
--- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java
+++ b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java
@@ -32,7 +32,6 @@
 /**
  * @author HyunGil Jeong
  */
-
 @RunWith(PinpointPluginTestSuite.class)
 @JvmVersion(7)
 @Dependency({ "org.mariadb.jdbc:mariadb-java-client:[1.4.min,1.6.min)", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2" })
@@ -47,6 +46,7 @@ public void testStatement() throws Exception {
 
         PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
         verifier.printCache();
+        verifier.verifyTraceCount(2);
 
         // Driver#connect(String, Properties)
         Class<?> driverClass = Class.forName("org.mariadb.jdbc.Driver");
diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java
new file mode 100644
index 000000000000..47394fb9af38
--- /dev/null
+++ b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2017 NAVER Corp.
+ *
+ * Licensed 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 com.navercorp.pinpoint.plugin.jdbc.mariadb;
+
+import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier;
+import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder;
+import com.navercorp.pinpoint.test.plugin.Dependency;
+import com.navercorp.pinpoint.test.plugin.JvmVersion;
+import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.args;
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.cachedArgs;
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event;
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.sql;
+
+/**
+ * <p>Notable class changes :<br/>
+ * <ul>
+ *     <li><tt>org.mariadb.jdbc.AbstractPrepareStatement</tt> -> <tt>org.mariadb.jdbc.BasePrepareStatement</tt></li>
+ *     <li><tt>org.mariadb.jdbc.MariaDbServerPreparedStatement</tt> -> <tt>org.mariadb.jdbc.MariaDbPreparedStatementServer</tt></li>
+ *     <li><tt>org.mariadb.jdbc.MariaDbClientPreparedStatement</tt> -> <tt>org.mariadb.jdbc.MariaDbPreparedStatementClient</tt></li>
+ *     <li><tt>org.mariadb.jdbc.AbstractCallableProcedureStatement</tt> -> <tt>org.mariadb.jdbc.CallableProcedureStatement</tt></li>
+ *     <li><tt>org.mariadb.jdbc.AbstractCallableFunctionStatement</tt> -> <tt>org.mariadb.jdbc.CallableFunctionStatement</tt></li>
+ * </ul>
+ * </p>
+ * <p>useServerPrepStmts defaults to false (was true before 1.6.0)
+ * </p>
+ *
+ * @author HyunGil Jeong
+ */
+@RunWith(PinpointPluginTestSuite.class)
+@JvmVersion(7) // 1.6.2+ works with Java 6, but since the IT includes 1.6.0 and 1.6.1 just run on Java 7
+@Dependency({ "org.mariadb.jdbc:mariadb-java-client:[1.6.0,2.0.min)", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2" })
+public class MariaDB_1_6_x_to_2_0_0_IT extends MariaDB_IT_Base {
+
+    // see CallableParameterMetaData#queryMetaInfos
+    private  static final String CALLABLE_QUERY_META_INFOS_QUERY = "select param_list, returns, db, type from mysql.proc where name=? and db=DATABASE()";
+
+    @Test
+    public void testStatement() throws Exception {
+        super.executeStatement();
+
+        PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
+        verifier.printCache();
+
+        // Driver#connect(String, Properties)
+        Class<?> driverClass = Class.forName("org.mariadb.jdbc.Driver");
+        Method connect = driverClass.getDeclaredMethod("connect", String.class, Properties.class);
+        verifier.verifyTrace(event("MARIADB", connect, null, URL, DATABASE_NAME, cachedArgs(JDBC_URL)));
+
+        // MariaDbStatement#executeQuery(String)
+        Class<?> mariaDbStatementClass = Class.forName("org.mariadb.jdbc.MariaDbStatement");
+        Method executeQuery = mariaDbStatementClass.getDeclaredMethod("executeQuery", String.class);
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQuery, null, URL, DATABASE_NAME, sql(STATEMENT_NORMALIZED_QUERY, "1")));
+    }
+
+    @Test
+    public void testPreparedStatement() throws Exception {
+        super.executePreparedStatement();
+
+        PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
+        verifier.printCache();
+        verifier.verifyTraceCount(3);
+
+        // Driver#connect(String, Properties)
+        Class<?> driverClass = Class.forName("org.mariadb.jdbc.Driver");
+        Method connect = driverClass.getDeclaredMethod("connect", String.class, Properties.class);
+        verifier.verifyTrace(event("MARIADB", connect, null, URL, DATABASE_NAME, cachedArgs(JDBC_URL)));
+
+        // MariaDbConnection#prepareStatement(String)
+        Class<?> mariaDbConnectionClass = Class.forName("org.mariadb.jdbc.MariaDbConnection");
+        Method prepareStatement = mariaDbConnectionClass.getDeclaredMethod("prepareStatement", String.class);
+        verifier.verifyTrace(event("MARIADB", prepareStatement, null, URL, DATABASE_NAME, sql(PREPARED_STATEMENT_QUERY, null)));
+
+        // MariaDbPreparedStatementClient#executeQuery
+        Class<?> mariaDbServerPreparedStatementClass = Class.forName("org.mariadb.jdbc.MariaDbPreparedStatementClient");
+        Method executeQuery = mariaDbServerPreparedStatementClass.getDeclaredMethod("executeQuery");
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQuery, null, URL, DATABASE_NAME, sql(PREPARED_STATEMENT_QUERY, null, "3")));
+    }
+
+    @Test
+    public void testCallableStatement() throws Exception {
+        super.executeCallableStatement();
+
+        PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
+        verifier.printCache();
+        verifier.verifyTraceCount(6);
+
+        // Driver#connect(String, Properties)
+        Class<?> driverClass = Class.forName("org.mariadb.jdbc.Driver");
+        Method connect = driverClass.getDeclaredMethod("connect", String.class, Properties.class);
+        verifier.verifyTrace(event("MARIADB", connect, null, URL, DATABASE_NAME, cachedArgs(JDBC_URL)));
+
+        // MariaDbConnection#prepareCall(String)
+        Class<?> mariaDbConnectionClass = Class.forName("org.mariadb.jdbc.MariaDbConnection");
+        Method prepareCall = mariaDbConnectionClass.getDeclaredMethod("prepareCall", String.class);
+        verifier.verifyTrace(event("MARIADB", prepareCall, null, URL, DATABASE_NAME, sql(CALLABLE_STATEMENT_QUERY, null)));
+
+        // CallableProcedureStatement#registerOutParameter
+        Class<?> abstractCallableProcedureStatementClass = Class.forName("org.mariadb.jdbc.CallableProcedureStatement");
+        Method registerOutParameter = abstractCallableProcedureStatementClass.getMethod("registerOutParameter", int.class, int.class);
+        verifier.verifyTrace(event("MARIADB", registerOutParameter, null, URL, DATABASE_NAME, args(2, CALLABLE_STATMENT_OUTPUT_PARAM_TYPE)));
+
+        // MariaDbPreparedStatementServer#executeQuery
+        Class<?> mariaDbPreparedStatementServerClass = Class.forName("org.mariadb.jdbc.MariaDbPreparedStatementServer");
+        Method executeQueryServer = mariaDbPreparedStatementServerClass.getDeclaredMethod("executeQuery");
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQueryServer, null, URL, DATABASE_NAME, sql(CALLABLE_STATEMENT_QUERY, null, CALLABLE_STATEMENT_INPUT_PARAM)));
+
+        // MariaDbConnection#prepareStatement(String)
+        Method prepareStatement = mariaDbConnectionClass.getDeclaredMethod("prepareStatement", String.class);
+        verifier.verifyTrace(event("MARIADB", prepareStatement, null, URL, DATABASE_NAME, sql(CALLABLE_QUERY_META_INFOS_QUERY, null)));
+
+        // MariaDbPreparedStatementClient#executeQuery
+        Class<?> mariaDbPreparedStatementClientClass = Class.forName("org.mariadb.jdbc.MariaDbPreparedStatementClient");
+        Method executeQueryClient = mariaDbPreparedStatementClientClass.getDeclaredMethod("executeQuery");
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQueryClient, null, URL, DATABASE_NAME, sql(CALLABLE_QUERY_META_INFOS_QUERY, null, PROCEDURE_NAME)));
+    }
+}
diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java
new file mode 100644
index 000000000000..679a8440e552
--- /dev/null
+++ b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2017 NAVER Corp.
+ *
+ * Licensed 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 com.navercorp.pinpoint.plugin.jdbc.mariadb;
+
+import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier;
+import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder;
+import com.navercorp.pinpoint.test.plugin.Dependency;
+import com.navercorp.pinpoint.test.plugin.JvmVersion;
+import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.args;
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.cachedArgs;
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event;
+import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.sql;
+
+/**
+ * @author HyunGil Jeong
+ */
+@RunWith(PinpointPluginTestSuite.class)
+@JvmVersion(8) // 2.x+ requires Java 8
+@Dependency({ "org.mariadb.jdbc:mariadb-java-client:[2.0.1,)", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2" })
+public class MariaDB_2_x_IT extends MariaDB_IT_Base {
+
+    // see CallableParameterMetaData#queryMetaInfos
+    private  static final String CALLABLE_QUERY_META_INFOS_QUERY = "select param_list, returns, db, type from mysql.proc where name=? and db=DATABASE()";
+
+    @Test
+    public void testStatement() throws Exception {
+        super.executeStatement();
+
+        PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
+        verifier.printCache();
+
+        // Driver#connect(String, Properties)
+        Class<?> driverClass = Class.forName("org.mariadb.jdbc.Driver");
+        Method connect = driverClass.getDeclaredMethod("connect", String.class, Properties.class);
+        verifier.verifyTrace(event("MARIADB", connect, null, URL, DATABASE_NAME, cachedArgs(JDBC_URL)));
+
+        // MariaDbStatement#executeQuery(String)
+        Class<?> mariaDbStatementClass = Class.forName("org.mariadb.jdbc.MariaDbStatement");
+        Method executeQuery = mariaDbStatementClass.getDeclaredMethod("executeQuery", String.class);
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQuery, null, URL, DATABASE_NAME, sql(STATEMENT_NORMALIZED_QUERY, "1")));
+    }
+
+    @Test
+    public void testPreparedStatement() throws Exception {
+        super.executePreparedStatement();
+
+        PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
+        verifier.printCache();
+        verifier.verifyTraceCount(3);
+
+        // Driver#connect(String, Properties)
+        Class<?> driverClass = Class.forName("org.mariadb.jdbc.Driver");
+        Method connect = driverClass.getDeclaredMethod("connect", String.class, Properties.class);
+        verifier.verifyTrace(event("MARIADB", connect, null, URL, DATABASE_NAME, cachedArgs(JDBC_URL)));
+
+        // MariaDbConnection#prepareStatement(String)
+        Class<?> mariaDbConnectionClass = Class.forName("org.mariadb.jdbc.MariaDbConnection");
+        Method prepareStatement = mariaDbConnectionClass.getDeclaredMethod("prepareStatement", String.class);
+        verifier.verifyTrace(event("MARIADB", prepareStatement, null, URL, DATABASE_NAME, sql(PREPARED_STATEMENT_QUERY, null)));
+
+        // MariaDbPreparedStatementClient#executeQuery
+        Class<?> mariaDbServerPreparedStatementClass = Class.forName("org.mariadb.jdbc.MariaDbPreparedStatementClient");
+        Method executeQuery = mariaDbServerPreparedStatementClass.getDeclaredMethod("executeQuery");
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQuery, null, URL, DATABASE_NAME, sql(PREPARED_STATEMENT_QUERY, null, "3")));
+    }
+
+    @Test
+    public void testCallableStatement() throws Exception {
+        super.executeCallableStatement();
+
+        PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance();
+        verifier.printCache();
+        verifier.verifyTraceCount(6);
+
+        // Driver#connect(String, Properties)
+        Class<?> driverClass = Class.forName("org.mariadb.jdbc.Driver");
+        Method connect = driverClass.getDeclaredMethod("connect", String.class, Properties.class);
+        verifier.verifyTrace(event("MARIADB", connect, null, URL, DATABASE_NAME, cachedArgs(JDBC_URL)));
+
+        // MariaDbConnection#prepareCall(String)
+        Class<?> mariaDbConnectionClass = Class.forName("org.mariadb.jdbc.MariaDbConnection");
+        Method prepareCall = mariaDbConnectionClass.getDeclaredMethod("prepareCall", String.class);
+        verifier.verifyTrace(event("MARIADB", prepareCall, null, URL, DATABASE_NAME, sql(CALLABLE_STATEMENT_QUERY, null)));
+
+        // CallableProcedureStatement#registerOutParameter
+        Class<?> abstractCallableProcedureStatementClass = Class.forName("org.mariadb.jdbc.CallableProcedureStatement");
+        Method registerOutParameter = abstractCallableProcedureStatementClass.getMethod("registerOutParameter", int.class, int.class);
+        verifier.verifyTrace(event("MARIADB", registerOutParameter, null, URL, DATABASE_NAME, args(2, CALLABLE_STATMENT_OUTPUT_PARAM_TYPE)));
+
+        // MariaDbPreparedStatementServer#executeQuery
+        Class<?> mariaDbPreparedStatementServerClass = Class.forName("org.mariadb.jdbc.MariaDbPreparedStatementServer");
+        Method executeQueryServer = mariaDbPreparedStatementServerClass.getDeclaredMethod("executeQuery");
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQueryServer, null, URL, DATABASE_NAME, sql(CALLABLE_STATEMENT_QUERY, null, CALLABLE_STATEMENT_INPUT_PARAM)));
+
+        // MariaDbConnection#prepareStatement(String)
+        Method prepareStatement = mariaDbConnectionClass.getDeclaredMethod("prepareStatement", String.class);
+        verifier.verifyTrace(event("MARIADB", prepareStatement, null, URL, DATABASE_NAME, sql(CALLABLE_QUERY_META_INFOS_QUERY, null)));
+
+        // MariaDbPreparedStatementClient#executeQuery
+        Class<?> mariaDbPreparedStatementClientClass = Class.forName("org.mariadb.jdbc.MariaDbPreparedStatementClient");
+        Method executeQueryClient = mariaDbPreparedStatementClientClass.getDeclaredMethod("executeQuery");
+        verifier.verifyTrace(event("MARIADB_EXECUTE_QUERY", executeQueryClient, null, URL, DATABASE_NAME, sql(CALLABLE_QUERY_META_INFOS_QUERY, null, PROCEDURE_NAME)));
+    }
+}