flyrain commented on code in PR #3385:
URL: https://github.com/apache/polaris/pull/3385#discussion_r2850534738


##########
persistence/relational-jdbc/src/main/java/org/apache/polaris/persistence/relational/jdbc/MetricsSchemaBootstrapUtil.java:
##########
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.polaris.persistence.relational.jdbc;
+
+import java.io.InputStream;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import 
org.apache.polaris.persistence.relational.jdbc.models.ModelScanMetricsReport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for bootstrapping and checking the metrics schema.
+ *
+ * <p>Metrics tables (scan_metrics_report and commit_metrics_report) are part 
of the unified schema
+ * (v4). This utility provides methods to:
+ *
+ * <ul>
+ *   <li>Check if metrics tables exist in the database
+ *   <li>Bootstrap metrics tables
+ *   <li>Get the current and latest schema versions
+ * </ul>
+ *
+ * <p>Metrics tables are created automatically during the standard bootstrap 
process. This utility
+ * is primarily used for:
+ *
+ * <ul>
+ *   <li>Checking if metrics tables exist before enabling metrics persistence
+ *   <li>Deployments using a separate datasource for metrics
+ * </ul>
+ */
+public final class MetricsSchemaBootstrapUtil {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(MetricsSchemaBootstrapUtil.class);
+
+  /** The latest schema version that includes metrics tables. */
+  public static final int LATEST_VERSION = 4;
+
+  /** SQL to check if the scan_metrics_report table exists by selecting from 
it. */
+  private static final String CHECK_TABLE_SQL =
+      "SELECT 1 FROM "
+          + 
QueryGenerator.getFullyQualifiedTableName(ModelScanMetricsReport.TABLE_NAME)
+          + " LIMIT 1";
+
+  private MetricsSchemaBootstrapUtil() {
+    // Utility class - no instantiation
+  }
+
+  /**
+   * Checks if the metrics tables exist in the database.
+   *
+   * <p>This method attempts to query the scan_metrics_report table. If the 
table doesn't exist, the
+   * query will fail with a "relation does not exist" error.
+   *
+   * @param datasourceOperations the datasource operations to use
+   * @return true if the scan_metrics_report table exists, false otherwise
+   */
+  public static boolean metricsTableExists(DatasourceOperations 
datasourceOperations) {
+    try {
+      datasourceOperations.runWithinTransaction(
+          connection -> {
+            try (PreparedStatement stmt = 
connection.prepareStatement(CHECK_TABLE_SQL);
+                ResultSet rs = stmt.executeQuery()) {
+              // Just need to execute - we don't care about results
+              return true;
+            }
+          });
+      return true;
+    } catch (SQLException e) {
+      if (datasourceOperations.isRelationDoesNotExist(e)) {
+        return false;
+      }
+      throw new IllegalStateException("Failed to check if metrics tables 
exist", e);
+    }
+  }
+
+  /**
+   * Bootstraps the metrics tables using the latest schema version.
+   *
+   * <p>This method is idempotent - if metrics tables already exist, it will 
not recreate them.
+   *
+   * @param datasourceOperations the datasource operations to use
+   * @param realmId the realm identifier (for logging purposes)
+   */
+  public static void bootstrap(DatasourceOperations datasourceOperations, 
String realmId) {
+    bootstrap(datasourceOperations, realmId, LATEST_VERSION);
+  }
+
+  /**
+   * Bootstraps the metrics tables using the specified schema version.
+   *
+   * <p>This method is idempotent - if metrics tables already exist, it will 
not recreate them.
+   *
+   * @param datasourceOperations the datasource operations to use
+   * @param realmId the realm identifier (for logging purposes)
+   * @param targetVersion the target schema version
+   */
+  public static void bootstrap(
+      DatasourceOperations datasourceOperations, String realmId, int 
targetVersion) {
+    if (targetVersion < LATEST_VERSION) {
+      throw new IllegalArgumentException(
+          String.format(
+              "Metrics tables require schema version %d or higher, but 
requested version %d",
+              LATEST_VERSION, targetVersion));
+    }
+
+    if (metricsTableExists(datasourceOperations)) {
+      LOGGER.info("Metrics tables already exist for realm '{}', skipping 
bootstrap", realmId);
+      return;
+    }
+
+    LOGGER.info("Bootstrapping metrics tables for realm '{}'...", realmId);
+    try {
+      InputStream scriptStream =
+          
datasourceOperations.getDatabaseType().openInitScriptResource(targetVersion);
+      datasourceOperations.executeScript(scriptStream);

Review Comment:
   this will result in executing the same schema file twice, which will fail 
fast, and metrics table won't be able to created



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to