Skip to content

Commit 9f6dfea

Browse files
authored
Merge pull request #2146 from newrelic/mariadb-updates
NR-336630-Full-support-for-r2dbc-maria-db-client - credit to @dhilpipre - clone of 2142
2 parents a57293a + ef4981c commit 9f6dfea

File tree

31 files changed

+1194
-5
lines changed

31 files changed

+1194
-5
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
dependencies {
2+
implementation(project(":agent-bridge"))
3+
implementation(project(":agent-bridge-datastore"))
4+
implementation("org.mariadb.jdbc:mariadb-java-client:3.0.3")
5+
6+
testImplementation("ch.vorburger.mariaDB4j:mariaDB4j:2.2.1")
7+
testImplementation(project(":instrumentation:jdbc-generic")){ transitive = false }
8+
}
9+
10+
jar {
11+
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.jdbc-mariadb-3.0.0' }
12+
}
13+
14+
verifyInstrumentation {
15+
passesOnly 'org.mariadb.jdbc:mariadb-java-client:(3.0.2-rc,)'
16+
exclude 'org.mariadb.jdbc:mariadb-java-client:[3.0.0-alpha,3.0.2-rc]'
17+
}
18+
19+
site {
20+
title 'MariaDB Java Client'
21+
type 'Datastore'
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
*
3+
* * Copyright 2020 New Relic Corporation. All rights reserved.
4+
* * SPDX-License-Identifier: Apache-2.0
5+
*
6+
*/
7+
8+
package com.nr.agent.instrumentation.jdbc.mariadb;
9+
10+
import com.newrelic.agent.bridge.datastore.DatabaseVendor;
11+
import com.newrelic.agent.bridge.datastore.DatastoreVendor;
12+
import com.newrelic.agent.bridge.datastore.JdbcDatabaseVendor;
13+
14+
public class MariaDbDatabaseVendor extends JdbcDatabaseVendor {
15+
16+
public static final DatabaseVendor INSTANCE = new MariaDbDatabaseVendor();
17+
18+
private MariaDbDatabaseVendor() {
19+
super("MariaDB", "mysql", false);
20+
}
21+
22+
@Override
23+
public DatastoreVendor getDatastoreVendor() {
24+
return DatastoreVendor.MySQL;
25+
}
26+
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
*
3+
* * Copyright 2020 New Relic Corporation. All rights reserved.
4+
* * SPDX-License-Identifier: Apache-2.0
5+
*
6+
*/
7+
8+
package org.mariadb.jdbc;
9+
10+
import java.util.Properties;
11+
12+
import com.newrelic.agent.bridge.datastore.JdbcHelper;
13+
import com.newrelic.api.agent.weaver.Weave;
14+
import com.newrelic.api.agent.weaver.Weaver;
15+
import com.nr.agent.instrumentation.jdbc.mariadb.MariaDbDatabaseVendor;
16+
17+
@Weave
18+
public abstract class Driver {
19+
20+
public Connection connect(String url, Properties props) {
21+
JdbcHelper.putVendor(getClass(), MariaDbDatabaseVendor.INSTANCE);
22+
return Weaver.callOriginal();
23+
}
24+
25+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
*
3+
* * Copyright 2020 New Relic Corporation. All rights reserved.
4+
* * SPDX-License-Identifier: Apache-2.0
5+
*
6+
*/
7+
8+
package org.mariadb.jdbc;
9+
10+
import java.sql.Connection;
11+
12+
import com.newrelic.agent.bridge.datastore.JdbcHelper;
13+
import com.newrelic.api.agent.weaver.Weave;
14+
import com.newrelic.api.agent.weaver.Weaver;
15+
import com.nr.agent.instrumentation.jdbc.mariadb.MariaDbDatabaseVendor;
16+
17+
@Weave
18+
public abstract class MariaDbDataSource {
19+
20+
public Connection getConnection() {
21+
JdbcHelper.putVendor(getClass(), MariaDbDatabaseVendor.INSTANCE);
22+
return Weaver.callOriginal();
23+
}
24+
25+
public Connection getConnection(String user, String password) {
26+
JdbcHelper.putVendor(getClass(), MariaDbDatabaseVendor.INSTANCE);
27+
return Weaver.callOriginal();
28+
}
29+
30+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
*
3+
* * Copyright 2020 New Relic Corporation. All rights reserved.
4+
* * SPDX-License-Identifier: Apache-2.0
5+
*
6+
*/
7+
8+
package org.mariadb.jdbc;
9+
10+
import java.sql.Connection;
11+
import java.sql.DriverManager;
12+
import java.sql.PreparedStatement;
13+
import java.sql.ResultSet;
14+
import java.sql.Statement;
15+
16+
import ch.vorburger.mariadb4j.DB;
17+
import ch.vorburger.mariadb4j.DBConfigurationBuilder;
18+
import com.newrelic.agent.introspec.DatastoreHelper;
19+
import com.newrelic.agent.introspec.InstrumentationTestConfig;
20+
import com.newrelic.agent.introspec.InstrumentationTestRunner;
21+
import com.newrelic.agent.introspec.Introspector;
22+
import com.newrelic.api.agent.Trace;
23+
import org.junit.AfterClass;
24+
import org.junit.Assert;
25+
import org.junit.BeforeClass;
26+
import org.junit.Ignore;
27+
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
30+
@RunWith(InstrumentationTestRunner.class)
31+
@InstrumentationTestConfig(includePrefixes = {"org.mariadb.jdbc"})
32+
public class MariaDbTest {
33+
34+
private static DB mariaDb;
35+
36+
private static String connectionString;
37+
private static String dbName;
38+
39+
@BeforeClass
40+
public static void setUpDb() throws Exception {
41+
DBConfigurationBuilder builder = DBConfigurationBuilder.newBuilder()
42+
.setPort(0); // This will automatically find a free port
43+
44+
dbName = "MariaDB" + System.currentTimeMillis();
45+
mariaDb = DB.newEmbeddedDB(builder.build());
46+
connectionString = builder.getURL(dbName);
47+
mariaDb.start();
48+
49+
mariaDb.createDB(dbName);
50+
mariaDb.source("maria-db-test.sql", null, null, dbName);
51+
}
52+
53+
@AfterClass
54+
public static void tearDownDb() throws Exception {
55+
mariaDb.stop();
56+
}
57+
58+
@Test
59+
@Ignore
60+
public void testPreparedStatementQuery() throws Exception {
61+
mariaDbPreparedStatementQuery();
62+
63+
Introspector introspector = InstrumentationTestRunner.getIntrospector();
64+
Assert.assertEquals(1, introspector.getFinishedTransactionCount());
65+
DatastoreHelper helper = new DatastoreHelper("MySQL");
66+
helper.assertAggregateMetrics();
67+
helper.assertUnscopedOperationMetricCount("select", 1);
68+
}
69+
70+
@Test
71+
@Ignore
72+
public void testCrud() throws Exception {
73+
mariaDbInsert();
74+
mariaDbReadInsert();
75+
mariaDbUpdate();
76+
mariaDbReadUpdate();
77+
mariaDbDelete();
78+
mariaDbReadDelete();
79+
80+
Introspector introspector = InstrumentationTestRunner.getIntrospector();
81+
Assert.assertEquals(6, introspector.getFinishedTransactionCount());
82+
83+
DatastoreHelper helper = new DatastoreHelper("MySQL");
84+
helper.assertAggregateMetrics();
85+
helper.assertUnscopedOperationMetricCount("insert", 1); // C
86+
helper.assertUnscopedOperationMetricCount("select", 3); // R (once per step)
87+
helper.assertUnscopedOperationMetricCount("update", 1); // U
88+
helper.assertUnscopedOperationMetricCount("delete", 1); // D
89+
}
90+
91+
@Trace(dispatcher = true)
92+
public void mariaDbPreparedStatementQuery() throws Exception {
93+
Connection connection = DriverManager.getConnection(connectionString, "root", "");
94+
PreparedStatement statement = connection.prepareStatement("SELECT id FROM testQuery WHERE value LIKE ?");
95+
statement.setString(1, "cool");
96+
ResultSet resultSet = statement.executeQuery();
97+
if (resultSet.next()) {
98+
long value = resultSet.getLong(1);
99+
Assert.assertEquals(1, value);
100+
} else {
101+
Assert.fail("Unable to get any results from database");
102+
}
103+
connection.close();
104+
}
105+
106+
@Trace(dispatcher = true)
107+
public void mariaDbInsert() throws Exception {
108+
Connection connection = DriverManager.getConnection(connectionString, "root", "");
109+
110+
PreparedStatement statement = connection.prepareStatement("INSERT INTO testCrud (id, value) VALUES (1, ?)");
111+
statement.setString(1, "insert");
112+
int inserted = statement.executeUpdate();
113+
Assert.assertEquals(1, inserted); // Only 1 row to insert
114+
connection.close();
115+
}
116+
117+
118+
@Trace(dispatcher = true)
119+
public void mariaDbReadInsert() throws Exception {
120+
Connection connection = DriverManager.getConnection(connectionString, "root", "");
121+
Statement statement = connection.createStatement();
122+
ResultSet resultSet = statement.executeQuery("SELECT id FROM testCrud WHERE value = 'insert'");
123+
if (resultSet.next()) {
124+
long value = resultSet.getLong(1);
125+
Assert.assertEquals(1, value);
126+
} else {
127+
Assert.fail("Unable to find inserted row");
128+
}
129+
connection.close();
130+
}
131+
132+
@Trace(dispatcher = true)
133+
public void mariaDbUpdate() throws Exception {
134+
Connection connection = DriverManager.getConnection(connectionString, "root", "");
135+
136+
PreparedStatement statement = connection.prepareStatement("UPDATE testCrud SET value = ? WHERE id = ?");
137+
statement.setString(1, "update");
138+
statement.setInt(2, 1);
139+
int updated = statement.executeUpdate();
140+
Assert.assertEquals(1, updated); // Only 1 row to update
141+
connection.close();
142+
}
143+
144+
@Trace(dispatcher = true)
145+
public void mariaDbReadUpdate() throws Exception {
146+
Connection connection = DriverManager.getConnection(connectionString, "root", "");
147+
Statement statement = connection.createStatement();
148+
statement.execute("SELECT value FROM testCrud WHERE id = 1");
149+
ResultSet resultSet = statement.getResultSet();
150+
if (resultSet.next()) {
151+
String value = resultSet.getString(1);
152+
Assert.assertEquals("update", value);
153+
} else {
154+
Assert.fail("Unable to find updated row");
155+
}
156+
connection.close();
157+
}
158+
159+
@Trace(dispatcher = true)
160+
public void mariaDbDelete() throws Exception {
161+
Connection connection = DriverManager.getConnection(connectionString, "root", "");
162+
163+
Statement statement = connection.createStatement();
164+
int updated = statement.executeUpdate("DELETE FROM testCrud WHERE id = 1");
165+
Assert.assertEquals(1, updated); // Only 1 row to remove
166+
connection.close();
167+
}
168+
169+
@Trace(dispatcher = true)
170+
public void mariaDbReadDelete() throws Exception {
171+
Connection connection = DriverManager.getConnection(connectionString, "root", "");
172+
PreparedStatement statement = connection.prepareStatement("SELECT * FROM testCrud");
173+
ResultSet resultSet = statement.executeQuery();
174+
Assert.assertFalse("We found a row when we didn't expect one", resultSet.next());
175+
connection.close();
176+
}
177+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATE TABLE testQuery (id int not null primary key, value varchar(20));
2+
INSERT INTO testQuery (id, value) VALUES (1, 'cool');
3+
INSERT INTO testQuery (id, value) VALUES (2, 'nice');
4+
INSERT INTO testQuery (id, value) VALUES (3, 'sweet');
5+
6+
CREATE TABLE testCrud (id int not null primary key, value varchar(20));
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
dependencies {
2+
implementation(project(":agent-bridge"))
3+
implementation(project(":agent-bridge-datastore"))
4+
implementation("org.mariadb:r2dbc-mariadb:1.1.2")
5+
testImplementation("ch.vorburger.mariaDB4j:mariaDB4j:2.2.1")
6+
}
7+
8+
jar {
9+
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.r2dbc-mariadb-1.1.2' }
10+
}
11+
12+
verifyInstrumentation {
13+
passesOnly 'org.mariadb:r2dbc-mariadb:[1.1.2,1.2.1)'
14+
excludeRegex(".*(alpha|beta|rc).*")
15+
}
16+
17+
site {
18+
title 'MariaDB R2DBC'
19+
type 'Datastore'
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.nr.agent.instrumentation.r2dbc;
2+
3+
public class CancelHandler implements Runnable {
4+
5+
private NRHolder holder = null;
6+
7+
public CancelHandler(NRHolder hold) {
8+
holder = hold;
9+
}
10+
11+
@Override
12+
public void run() {
13+
if (holder != null) {
14+
holder.ignore();
15+
}
16+
}
17+
18+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.nr.agent.instrumentation.r2dbc;
2+
3+
import com.newrelic.api.agent.DatastoreParameters;
4+
import com.newrelic.api.agent.NewRelic;
5+
import com.newrelic.api.agent.Segment;
6+
7+
import java.util.function.Consumer;
8+
9+
public class NRHolder implements Consumer<Throwable>, Runnable {
10+
11+
private Segment segment = null;
12+
private DatastoreParameters params = null;
13+
14+
public NRHolder(Segment seg, DatastoreParameters p) {
15+
segment = seg;
16+
params = p;
17+
}
18+
19+
@Override
20+
public void accept(Throwable t) {
21+
NewRelic.noticeError(t);
22+
segment.ignore();
23+
segment = null;
24+
25+
}
26+
27+
@Override
28+
public void run() {
29+
if (segment != null) {
30+
if (params != null) {
31+
segment.reportAsExternal(params);
32+
}
33+
segment.end();
34+
segment = null;
35+
}
36+
}
37+
38+
public void ignore() {
39+
if (segment != null) {
40+
segment.ignore();
41+
segment = null;
42+
}
43+
}
44+
45+
}

0 commit comments

Comments
 (0)