Merge branch 'stable-2.16'
* stable-2.16:
Fix index creation when using MySQL
Upgrade bazlets to latest stable-2.16 to build with 2.16.1 API
Bazel: Include eclipse-out directory in .bazelignore
Add explanatory comment to empty BUILD file(s)
Change-Id: Ie8b952b296285f9f72d112e10b1cfef288403e2e
diff --git a/.bazelignore b/.bazelignore
new file mode 100644
index 0000000..30f1613
--- /dev/null
+++ b/.bazelignore
@@ -0,0 +1 @@
+eclipse-out
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java
index 05f663f..9e538e6 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java
@@ -48,7 +48,7 @@
class SQLClient {
private static final Logger log = LoggerFactory.getLogger(SQLClient.class);
private final Gson gson;
- private final boolean isPostgresql;
+ private final SQLDialect databaseDialect;
private HikariDataSource ds;
@@ -56,7 +56,8 @@
ds = new HikariDataSource(config);
gson = new GsonBuilder().registerTypeAdapter(Supplier.class, new SupplierSerializer()).create();
- isPostgresql = config.getJdbcUrl().contains("postgresql");
+
+ databaseDialect = SQLDialect.fromJdbcUrl(config.getJdbcUrl());
}
/**
@@ -65,8 +66,8 @@
* @throws SQLException If there was a problem with the database
*/
void createDBIfNotCreated() throws SQLException {
- execute(SQLTable.createTableQuery(isPostgresql));
- execute(SQLTable.createIndexes(isPostgresql));
+ execute(SQLTable.createTableQuery(databaseDialect));
+ execute(SQLTable.createIndexes(databaseDialect));
}
/**
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLDialect.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLDialect.java
new file mode 100644
index 0000000..48c246a
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLDialect.java
@@ -0,0 +1,39 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.ericsson.gerrit.plugins.eventslog.sql;
+
+/** SQLDialect provides enumerations for the various supported dialects of SQL. */
+public enum SQLDialect {
+ H2,
+ MYSQL,
+ POSTGRESQL;
+
+ /**
+ * This attempts to determine the SQL dialect from the JDBC URL.
+ * If the URL does not match one of the supported dialects, then
+ * H2 will be returned by default.
+ *
+ * @param jdbcUrl The JDBC URL.
+ * @return The dialect for the JDBC URL.
+ */
+ public static SQLDialect fromJdbcUrl(String jdbcUrl) {
+ if (jdbcUrl.contains("postgresql")) {
+ return POSTGRESQL;
+ } else if (jdbcUrl.contains("mysql")) {
+ return MYSQL;
+ }
+ return H2;
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLTable.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLTable.java
index 0db07a2..6093a38 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLTable.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLTable.java
@@ -23,9 +23,28 @@
static final String DATE_ENTRY = "date_created";
static final String EVENT_ENTRY = "event_info";
+ /** This is the name of the index that tracks the created date. */
private static final String CREATED_INDEX = "created_idx";
+ /** This is the name of the index that tracks the project. */
private static final String PROJECT_INDEX = "project_idx";
+ /**
+ * This is the H2 idempotent index-creation query format. Inputs, in order: index-name,
+ * table-name, index-column
+ */
private static final String H2_INDEX_CREATION_FORMAT = "CREATE INDEX IF NOT EXISTS %s ON %s (%s)";
+ /**
+ * This is the MySQL idempotent index-creation query format. Inputs, in order: table-name,
+ * index-name, table-name, index-name, index-column
+ */
+ private static final String MYSQL_INDEX_CREATION_FORMAT =
+ "SET @x := (SELECT COUNT(*) FROM information_schema.statistics WHERE table_name = '%s' AND index_name = '%s' AND table_schema = DATABASE());\n"
+ + "SET @sql := IF( @x > 0, 'SELECT ''Index exists.''', 'ALTER TABLE %s ADD INDEX %s (%s);');\n"
+ + "PREPARE stmt FROM @sql;\n"
+ + "EXECUTE stmt";
+ /**
+ * This is the Postgres idempotent index-creation query format. Inputs, in order: index-name,
+ * index-name, table-name, index-column
+ */
private static final String POSTGRESQL_INDEX_CREATION_FORMAT =
"DO $$\n"
+ "BEGIN\n"
@@ -42,13 +61,17 @@
private SQLTable() {}
- static String createTableQuery(boolean postgresql) {
+ static String createTableQuery(SQLDialect databaseDialect) {
StringBuilder query = new StringBuilder(140);
query.append(format("CREATE TABLE IF NOT EXISTS %s(", TABLE_NAME));
- if (postgresql) {
- query.append(format("%s SERIAL PRIMARY KEY,", PRIMARY_ENTRY));
- } else {
- query.append(format("%s INT AUTO_INCREMENT PRIMARY KEY,", PRIMARY_ENTRY));
+ switch (databaseDialect) {
+ case POSTGRESQL:
+ query.append(format("%s SERIAL PRIMARY KEY,", PRIMARY_ENTRY));
+ break;
+ case MYSQL:
+ case H2:
+ default:
+ query.append(format("%s INT AUTO_INCREMENT PRIMARY KEY,", PRIMARY_ENTRY));
}
query.append(format("%s VARCHAR(255),", PROJECT_ENTRY));
query.append(format("%s TIMESTAMP DEFAULT NOW(),", DATE_ENTRY));
@@ -56,11 +79,19 @@
return query.toString();
}
- static String createIndexes(boolean postgresql) {
- return postgresql ? getPostgresqlQuery() : getH2Query();
+ static String createIndexes(SQLDialect databaseDialect) {
+ switch (databaseDialect) {
+ case POSTGRESQL:
+ return getPostgresqlIndexQuery();
+ case MYSQL:
+ return getMysqlIndexQuery();
+ case H2:
+ default:
+ return getH2IndexQuery();
+ }
}
- private static String getPostgresqlQuery() {
+ private static String getPostgresqlIndexQuery() {
StringBuilder query = new StringBuilder(540);
query.append(
format(
@@ -80,7 +111,29 @@
return query.toString();
}
- private static String getH2Query() {
+ private static String getMysqlIndexQuery() {
+ StringBuilder query = new StringBuilder();
+ query.append(
+ format(
+ MYSQL_INDEX_CREATION_FORMAT,
+ TABLE_NAME,
+ CREATED_INDEX,
+ TABLE_NAME,
+ CREATED_INDEX,
+ DATE_ENTRY));
+ query.append(";");
+ query.append(
+ format(
+ MYSQL_INDEX_CREATION_FORMAT,
+ TABLE_NAME,
+ PROJECT_INDEX,
+ TABLE_NAME,
+ PROJECT_INDEX,
+ PROJECT_ENTRY));
+ return query.toString();
+ }
+
+ private static String getH2IndexQuery() {
StringBuilder query = new StringBuilder();
query.append(format(H2_INDEX_CREATION_FORMAT, CREATED_INDEX, TABLE_NAME, DATE_ENTRY));
query.append(";");
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 4421212..1c74a20 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -26,6 +26,10 @@
plugin.@PLUGIN@.storeUrl
: Specify the path to the directory in which to keep the database. When not
specified, the default path is jdbc:h2:\<gerrit_site>/data/db.
+ Supported database engines:
+* h2 (default)
+* postgresql
+* mysql
plugin.@PLUGIN@.localStorePath
: Specify the path to the directory in which to keep the back up database.
@@ -42,8 +46,12 @@
plugin.@PLUGIN@.urlOptions
: Options to append to the database url. Each option should be specified in a
separate line using the option=value format. For example:
- urlOptions = loglevel=INFO
- urlOptions = logUnclosedConnections=true
+* `urlOptions = loglevel=INFO`
+* `urlOptions = logUnclosedConnections=true`
+
+When using `mysql`, this option must be specified:
+
+* `urlOptions = allowMultiQueries=true`
plugin.@PLUGIN@.maxTries
: Maximum number of times the plugin should attempt to store the event if a
diff --git a/src/test/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLDialectTest.java b/src/test/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLDialectTest.java
new file mode 100644
index 0000000..60b7cb1
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLDialectTest.java
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// 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.ericsson.gerrit.plugins.eventslog.sql;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class SQLDialectTest {
+ @Test
+ public void defaultIsH2() throws Exception {
+ assertThat(SQLDialect.fromJdbcUrl("")).isEqualTo(SQLDialect.H2);
+ assertThat(SQLDialect.fromJdbcUrl("jdbc:")).isEqualTo(SQLDialect.H2);
+ assertThat(SQLDialect.fromJdbcUrl("jdbc:whatever://")).isEqualTo(SQLDialect.H2);
+ }
+
+ @Test
+ public void mysqlIsParsed() throws Exception {
+ assertThat(SQLDialect.fromJdbcUrl("jdbc:mysql://")).isEqualTo(SQLDialect.MYSQL);
+ }
+
+ @Test
+ public void postgresqlIsParsed() throws Exception {
+ assertThat(SQLDialect.fromJdbcUrl("jdbc:postgresql://")).isEqualTo(SQLDialect.POSTGRESQL);
+ }
+}
diff --git a/tools/bzl/BUILD b/tools/bzl/BUILD
index e69de29..c5ed0b7 100644
--- a/tools/bzl/BUILD
+++ b/tools/bzl/BUILD
@@ -0,0 +1 @@
+# Empty file required by Bazel