This is an automated email from the ASF dual-hosted git repository.
yuqi1129 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new e6a3a05571 [#12516] improvement(scripts): Add IF NOT EXISTS to CREATE
INDEX in upgrade SQL scripts for idempotency (#12968)
e6a3a05571 is described below
commit e6a3a055715dbf782ad9519f849429414ea1f0c6
Author: li jie <[email protected]>
AuthorDate: Thu Oct 29 16:28:37 2026 +0800
[#12516] improvement(scripts): Add IF NOT EXISTS to CREATE INDEX in upgrade
SQL scripts for idempotency (#12968)
### What changes were proposed in this pull request?
PostgreSQL: add `IF NOT EXISTS` to the 5 `CREATE INDEX` statements in
`scripts/postgresql/upgrade-1.1.0-to-1.2.0-postgresql.sql`. After this
change, every statement in the script is guarded by `IF NOT EXISTS` or
is naturally idempotent (`COMMENT ON`), so the whole upgrade script can
be safely re-run after a partial or completed run.
Add `testUpgradeToOneTwoIsIdempotent` to `TestSQLScripts` to verify the
PostgreSQL 1.1.0-to-1.2.0 upgrade script can be re-run as a whole, and
that the created indexes exist with the expected columns and uniqueness.
The test is skipped for non-PostgreSQL backends; retrying other upgrade
scripts is out of scope.
### Why are the changes needed?
A failed upgrade can leave committed changes behind. Re-running the
1.1.0-to-1.2.0 PostgreSQL upgrade script then fails on the
already-created indexes, preventing recovery through a normal retry.
Per review, this PR is now PostgreSQL-only:
- MySQL changes were dropped: MySQL 8.0 does not support `CREATE INDEX
IF NOT EXISTS`, and guarding only index creation does not make the whole
MySQL upgrade retryable (`ADD COLUMN`, `DROP INDEX`, `RENAME INDEX`
would still fail). Full MySQL upgrade-script idempotency will be tracked
in a separate issue.
- The 1.3.0-to-2.0.0 scripts are already retryable thanks to #13689.
Fixes #12516
### Does this PR introduce _any_ user-facing change?
No API or configuration changes. Operators can now re-run the PostgreSQL
1.1.0-to-1.2.0 upgrade script after a partial or completed run.
### How was this patch tested?
- Full `TestSQLScripts` suite passed locally (embedded H2 mode; the new
test skips non-PostgreSQL backends).
- The PostgreSQL path is exercised by CI with Docker: `./gradlew
:core:test --tests org.apache.gravitino.storage.TestSQLScripts -PskipITs
-PskipDockerTests=false`
Co-authored-by: lijie <[email protected]>
---
.../apache/gravitino/storage/TestSQLScripts.java | 35 ++++++++++++++++++++++
.../upgrade-1.1.0-to-1.2.0-postgresql.sql | 10 +++----
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git
a/core/src/test/java/org/apache/gravitino/storage/TestSQLScripts.java
b/core/src/test/java/org/apache/gravitino/storage/TestSQLScripts.java
index 45158c6eb8..a79089aa8b 100644
--- a/core/src/test/java/org/apache/gravitino/storage/TestSQLScripts.java
+++ b/core/src/test/java/org/apache/gravitino/storage/TestSQLScripts.java
@@ -134,6 +134,41 @@ public class TestSQLScripts extends TestJDBCBackend {
}
}
+ /**
+ * Verifies the PostgreSQL 1.1.0-to-1.2.0 upgrade script can be re-run as a
whole after a
+ * completed upgrade: every statement is guarded by IF NOT EXISTS or is
naturally idempotent
+ * (COMMENT ON). The scope is limited to this script; other upgrade scripts
are not claimed to be
+ * retryable. The created indexes must exist with the expected columns and
uniqueness.
+ */
+ @TestTemplate
+ public void testUpgradeToOneTwoIsIdempotent() throws SQLException,
IOException {
+ if (!"postgresql".equals(backendType)) {
+ return;
+ }
+ Path scriptDir = upgradeScriptDirectory();
+ File upgrade =
scriptDir.resolve("upgrade-1.1.0-to-1.2.0-postgresql.sql").toFile();
+ dropAllTables();
+ executeScript(scriptDir.resolve("schema-1.1.0-postgresql.sql").toFile());
+ executeScript(upgrade);
+ // A retry after a completed upgrade must succeed; no statement may fail
again.
+ executeScript(upgrade);
+
+ // Index entries are formatted as "table:index name:ordinal
position:column:non-unique".
+ List<String> indexes = readSchemaIndexes(Set.of("function_meta",
"function_version_info"));
+ List<String> expectedIndexes =
+ List.of(
+ "function_meta:idx_function_meta_catalog_id:1:catalog_id:true",
+ "function_meta:idx_function_meta_metalake_id:1:metalake_id:true",
+
"function_version_info:idx_function_version_catalog_id:1:catalog_id:true",
+
"function_version_info:idx_function_version_metalake_id:1:metalake_id:true",
+
"function_version_info:idx_function_version_schema_id:1:schema_id:true");
+ for (String expectedIndex : expectedIndexes) {
+ Assertions.assertTrue(
+ indexes.contains(expectedIndex),
+ "Expected index entry missing after the re-run: " + expectedIndex);
+ }
+ }
+
/**
* Verifies every MySQL upgrade script from 0.5.0 onward can be re-run as a
whole after a
* completed upgrade: guarded DDL (ADD COLUMN, DROP INDEX, CREATE INDEX,
...) must skip instead of
diff --git a/scripts/postgresql/upgrade-1.1.0-to-1.2.0-postgresql.sql
b/scripts/postgresql/upgrade-1.1.0-to-1.2.0-postgresql.sql
index e75d75735a..4ce84aaf77 100644
--- a/scripts/postgresql/upgrade-1.1.0-to-1.2.0-postgresql.sql
+++ b/scripts/postgresql/upgrade-1.1.0-to-1.2.0-postgresql.sql
@@ -32,8 +32,8 @@ CREATE TABLE IF NOT EXISTS function_meta (
PRIMARY KEY (function_id),
UNIQUE (schema_id, function_name, deleted_at)
);
-CREATE INDEX idx_function_meta_metalake_id ON function_meta (metalake_id);
-CREATE INDEX idx_function_meta_catalog_id ON function_meta (catalog_id);
+CREATE INDEX IF NOT EXISTS idx_function_meta_metalake_id ON function_meta
(metalake_id);
+CREATE INDEX IF NOT EXISTS idx_function_meta_catalog_id ON function_meta
(catalog_id);
COMMENT ON TABLE function_meta IS 'function metadata';
COMMENT ON COLUMN function_meta.function_id IS 'function id';
@@ -61,9 +61,9 @@ CREATE TABLE IF NOT EXISTS function_version_info (
PRIMARY KEY (id),
UNIQUE (function_id, version, deleted_at)
);
-CREATE INDEX idx_function_version_metalake_id ON function_version_info
(metalake_id);
-CREATE INDEX idx_function_version_catalog_id ON function_version_info
(catalog_id);
-CREATE INDEX idx_function_version_schema_id ON function_version_info
(schema_id);
+CREATE INDEX IF NOT EXISTS idx_function_version_metalake_id ON
function_version_info (metalake_id);
+CREATE INDEX IF NOT EXISTS idx_function_version_catalog_id ON
function_version_info (catalog_id);
+CREATE INDEX IF NOT EXISTS idx_function_version_schema_id ON
function_version_info (schema_id);
COMMENT ON TABLE function_version_info IS 'function version info';
COMMENT ON COLUMN function_version_info.id IS 'auto increment id';