diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eb0a3477e6..6cfc44da97 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,8 +52,7 @@ cel-bom = { module = "org.projectnessie.cel:cel-bom", version = "0.5.3" } commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.20.0" } commons-text = { module = "org.apache.commons:commons-text", version = "1.15.0" } errorprone = { module = "com.google.errorprone:error_prone_core", version = "2.45.0" } -google-cloud-iamcredentials = { module = "com.google.cloud:google-cloud-iamcredentials", version = "2.80.0" } -google-cloud-storage-bom = { module = "com.google.cloud:google-cloud-storage-bom", version = "2.60.0" } +google-cloud-libraries-bom = { module = "com.google.cloud:libraries-bom", version = "26.72.0" } guava = { module = "com.google.guava:guava", version = "33.5.0-jre" } h2 = { module = "com.h2database:h2", version = "2.4.240" } dnsjava = { module = "dnsjava:dnsjava", version = "3.6.3" } diff --git a/gradle/projects.main.properties b/gradle/projects.main.properties index 3706c6f132..e617944a2f 100644 --- a/gradle/projects.main.properties +++ b/gradle/projects.main.properties @@ -33,6 +33,7 @@ polaris-admin=runtime/admin polaris-runtime-common=runtime/common polaris-runtime-test-common=runtime/test-common polaris-relational-jdbc=persistence/relational-jdbc +polaris-google-cloud-spanner=persistence/google-cloud-spanner polaris-tests=integration-tests aggregated-license-report=aggregated-license-report polaris-immutables=tools/immutables diff --git a/persistence/google-cloud-spanner/build.gradle.kts b/persistence/google-cloud-spanner/build.gradle.kts new file mode 100644 index 0000000000..e6d2f12344 --- /dev/null +++ b/persistence/google-cloud-spanner/build.gradle.kts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +plugins { + id("polaris-server") + id("org.kordamp.gradle.jandex") +} + +dependencies { + implementation(project(":polaris-core")) + implementation(libs.slf4j.api) + implementation(libs.guava) + + implementation(platform(libs.google.cloud.libraries.bom)) + implementation("com.google.cloud:google-cloud-spanner") + + compileOnly(libs.jakarta.annotation.api) + compileOnly(libs.jakarta.enterprise.cdi.api) + compileOnly(libs.jakarta.inject.api) + + compileOnly(libs.smallrye.common.annotation) // @Identifier + compileOnly(libs.smallrye.config.core) // @ConfigMapping + + testImplementation(libs.mockito.junit.jupiter) + testImplementation(libs.h2) + testImplementation(testFixtures(project(":polaris-core"))) +} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/DatabaseAdminClientSupplier.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/DatabaseAdminClientSupplier.java new file mode 100644 index 0000000000..559d460397 --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/DatabaseAdminClientSupplier.java @@ -0,0 +1,25 @@ +/* + * 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.spanner; + +import com.google.cloud.spanner.DatabaseAdminClient; +import java.util.function.Supplier; + +public interface DatabaseAdminClientSupplier extends Supplier {} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/DatabaseClientSupplier.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/DatabaseClientSupplier.java new file mode 100644 index 0000000000..9864b9123f --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/DatabaseClientSupplier.java @@ -0,0 +1,25 @@ +/* + * 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.spanner; + +import com.google.cloud.spanner.DatabaseClient; +import java.util.function.Supplier; + +public interface DatabaseClientSupplier extends Supplier {} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/GoogleCloudSpannerConfiguration.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/GoogleCloudSpannerConfiguration.java new file mode 100644 index 0000000000..2d6883ba10 --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/GoogleCloudSpannerConfiguration.java @@ -0,0 +1,37 @@ +/* + * 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.spanner; + +import io.smallrye.config.ConfigMapping; +import java.util.Optional; + +@ConfigMapping(prefix = "polaris.persistence.spanner") +public interface GoogleCloudSpannerConfiguration { + + public Optional quotaProjectId(); + + public Optional projectId(); + + public Optional instanceId(); + + public Optional databaseId(); + + public Optional emulatorHost(); +} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/GoogleCloudSpannerDatabaseClientLifecycleManager.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/GoogleCloudSpannerDatabaseClientLifecycleManager.java new file mode 100644 index 0000000000..d0c5274ba2 --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/GoogleCloudSpannerDatabaseClientLifecycleManager.java @@ -0,0 +1,112 @@ +/* + * 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.spanner; + +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseAdminClient; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.Dialect; +import com.google.cloud.spanner.Spanner; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import org.apache.polaris.core.persistence.bootstrap.SchemaOptions; +import org.apache.polaris.persistence.spanner.util.SpannerUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +public class GoogleCloudSpannerDatabaseClientLifecycleManager { + + private static final Logger LOGGER = + LoggerFactory.getLogger(GoogleCloudSpannerDatabaseClientLifecycleManager.class); + + protected final GoogleCloudSpannerConfiguration spannerConfiguration; + protected final Spanner spanner; + protected final DatabaseId databaseId; + + public GoogleCloudSpannerDatabaseClientLifecycleManager( + GoogleCloudSpannerConfiguration spannerConfiguration) { + this.spannerConfiguration = spannerConfiguration; + spanner = SpannerUtil.spannerFromConfiguration(spannerConfiguration); + databaseId = SpannerUtil.databaseFromConfiguration(spannerConfiguration); + } + + protected List getSpannerDatabaseDdl(SchemaOptions options) { + final InputStream schemaStream; + int schemaVersion = options.schemaVersion().orElse(1); + if (schemaVersion != 1) { + throw new IllegalArgumentException("Unknown or invalid schema version " + schemaVersion); + } + + schemaStream = getClass().getResourceAsStream("/spanner/schema-v1.sql"); + try (schemaStream) { + String schema = new String(schemaStream.readAllBytes(), Charset.forName("UTF-8")); + List lines = new ArrayList<>(); + for (String s : schema.split("\n")) { + s = s.trim(); + // Drop comments and empty lines. + if (s.startsWith("--") || s.length() == 0 || s.equals(";")) { + continue; + } + lines.add(s); + } + return List.of(String.join(" ", lines).split(";")); + } catch (IOException e) { + throw new RuntimeException("Unable to retrieve DDL statements", e); + } + } + + @Produces + public SchemaInitializer getSchemaInitializer() { + return (options) -> { + List ddlStatements = getSpannerDatabaseDdl(options); + LOGGER.info( + "Attempting to initialize Spanner database DDL with {} statements,", + ddlStatements.size()); + DatabaseAdminClient client = spanner.getDatabaseAdminClient(); + Database dbInfo = + client.newDatabaseBuilder(databaseId).setDialect(Dialect.GOOGLE_STANDARD_SQL).build(); + try { + client.updateDatabaseDdl(dbInfo, ddlStatements, null).get(); + LOGGER.info("Successfully applied DDL update."); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException( + "Unable to update Spanner DDL. Please disable this option for this database configuration.", + e); + } + }; + } + + @Produces + public DatabaseClientSupplier getDatabaseClientSupplier() { + return () -> spanner.getDatabaseClient(databaseId); + } + + @Produces + public DatabaseAdminClientSupplier getDatabaseAdminClientSupplier() { + return () -> spanner.getDatabaseAdminClient(); + } +} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/SchemaInitializer.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/SchemaInitializer.java new file mode 100644 index 0000000000..eb818268bc --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/SchemaInitializer.java @@ -0,0 +1,25 @@ +/* + * 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.spanner; + +import java.util.function.Consumer; +import org.apache.polaris.core.persistence.bootstrap.SchemaOptions; + +public interface SchemaInitializer extends Consumer {} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/model/Realm.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/model/Realm.java new file mode 100644 index 0000000000..2c7af6f72a --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/model/Realm.java @@ -0,0 +1,36 @@ +/* + * 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.spanner.model; + +import com.google.cloud.spanner.Key; +import com.google.cloud.spanner.Mutation; + +public final class Realm { + + public static final String TABLE_NAME = "Realms"; + + public static Mutation upsert(String realmId) { + return Mutation.newInsertOrUpdateBuilder(TABLE_NAME).set("RealmId").to(realmId).build(); + } + + public static Mutation delete(String realmId) { + return Mutation.delete(TABLE_NAME, Key.of(realmId)); + } +} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/util/Modifier.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/util/Modifier.java new file mode 100644 index 0000000000..9f875c10d5 --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/util/Modifier.java @@ -0,0 +1,57 @@ +/* + * 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.spanner.util; + +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +public final class Modifier { + T wrapped; + + protected Modifier(T wrapped) { + this.wrapped = wrapped; + } + + public Modifier apply(Function fn) { + wrapped = fn.apply(wrapped); + return this; + } + + public Modifier orElse(Optional toApply, V other, BiFunction fn) { + wrapped = fn.apply(wrapped, toApply.orElse(other)); + return this; + } + + public Modifier ifPresent(Optional toApply, BiFunction fn) { + if (toApply.isPresent()) { + wrapped = fn.apply(wrapped, toApply.get()); + } + return this; + } + + public T get() { + return wrapped; + } + + public static Modifier of(T value) { + return new Modifier<>(value); + } +} diff --git a/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/util/SpannerUtil.java b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/util/SpannerUtil.java new file mode 100644 index 0000000000..ee9786a0fa --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/java/org/apache/polaris/persistence/spanner/util/SpannerUtil.java @@ -0,0 +1,154 @@ +/* + * 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.spanner.util; + +import com.google.cloud.ServiceOptions; +import com.google.cloud.spanner.DatabaseId; +import com.google.cloud.spanner.Dialect; +import com.google.cloud.spanner.InstanceId; +import com.google.cloud.spanner.Key; +import com.google.cloud.spanner.KeySet; +import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.Spanner; +import com.google.cloud.spanner.SpannerOptions; +import com.google.cloud.spanner.Struct; +import com.google.cloud.spanner.StructReader; +import com.google.cloud.spanner.Type; +import com.google.cloud.spanner.Value; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Optional; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import org.apache.polaris.persistence.spanner.GoogleCloudSpannerConfiguration; + +public final class SpannerUtil { + + public static final String INT64_TYPE = + Type.int64().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL); + public static final String STRING_TYPE = + Type.string().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL); + + public static final String JSON_TYPE = + Type.json().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL); + + private static final Gson GSON = new Gson(); + + public static Value jsonValue(Map properties) { + JsonObject jsonObject = new JsonObject(); + if (properties != null) { + properties.forEach(jsonObject::addProperty); + } + return Value.json(jsonObject.toString()); + } + + public static Map jsonMap(String properties) { + HashMap map = new HashMap<>(); + if (properties != null && !properties.isBlank()) { + JsonObject obj = GSON.fromJson(properties, JsonObject.class); + obj.asMap().forEach((k, v) -> map.put(k, v.toString())); + } + return map; + } + + public static KeySet asKeySet(Iterable keys) { + KeySet.Builder builder = KeySet.newBuilder(); + for (Key key : keys) { + builder = builder.addKey(key); + } + return builder.build(); + } + + public static Struct column( + String name, String spannerType, boolean nullable, boolean primaryKey) { + return Struct.newBuilder() + .set("Name") + .to(name) + .set("Type") + .to(spannerType) + .set("Nullable") + .to(nullable) + .set("PrimaryKey") + .to(primaryKey) + .build(); + } + + public static Optional projectFromConfiguration(GoogleCloudSpannerConfiguration config) { + // If the quota project is set use that. + if (config.quotaProjectId().isPresent()) { + return config.quotaProjectId(); + } + + if (config.databaseId().isPresent()) { + String databaseId = config.databaseId().get(); + if (databaseId.startsWith("project")) { + return Optional.ofNullable(DatabaseId.of(databaseId).getInstanceId().getProject()); + } + } + return config.projectId(); + } + + public static DatabaseId databaseFromConfiguration(GoogleCloudSpannerConfiguration config) { + String databaseId = config.databaseId().orElseThrow(); + if (databaseId.startsWith("project")) { + return DatabaseId.of(databaseId); + } + String instanceId = config.instanceId().orElseThrow(); + if (instanceId.startsWith("project")) { + return DatabaseId.of(instanceId + "/" + databaseId); + } else { + return DatabaseId.of(InstanceId.of(config.projectId().orElseThrow(), instanceId), databaseId); + } + } + + public static Spanner spannerFromConfiguration(GoogleCloudSpannerConfiguration config) { + return Modifier.of(SpannerOptions.newBuilder()) + .ifPresent(projectFromConfiguration(config), ServiceOptions.Builder::setProjectId) + .ifPresent(config.emulatorHost(), SpannerOptions.Builder::setEmulatorHost) + .get() + .build() + .getService(); + } + + public static Iterator asIterator(final ResultSet resultSet) { + return new Iterator() { + + @Override + public boolean hasNext() { + return resultSet.next(); + } + + @Override + public StructReader next() { + return resultSet; + } + }; + } + + public static Stream asStream(final ResultSet resultSet) { + return StreamSupport.stream( + Spliterators.spliteratorUnknownSize(asIterator(resultSet), Spliterator.ORDERED), false); + } +} diff --git a/persistence/google-cloud-spanner/src/main/resources/spanner/schema-v1.sql b/persistence/google-cloud-spanner/src/main/resources/spanner/schema-v1.sql new file mode 100644 index 0000000000..c503a756bd --- /dev/null +++ b/persistence/google-cloud-spanner/src/main/resources/spanner/schema-v1.sql @@ -0,0 +1,86 @@ +-- +-- 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. + +CREATE SEQUENCE IF NOT EXISTS Ids OPTIONS(sequence_kind = 'bit_reversed_positive'); + +CREATE TABLE IF NOT EXISTS Realms( + RealmId STRING(MAX) NOT NULL +) +PRIMARY KEY (RealmId); + +CREATE TABLE IF NOT EXISTS Entities( +RealmId STRING(MAX) NOT NULL, +CatalogId INT64 NOT NULL, +Id INT64 NOT NULL, +ParentId INT64 NOT NULL, +Name STRING(MAX), +EntityVersion INT64 NOT NULL, +TypeCode INT64 NOT NULL, +SubTypeCode INT64 NOT NULL, +CreateTimestamp INT64, +DropTimestamp INT64, +PurgeTimestamp INT64, +ToPurgeTimestamp INT64, +LastUpdateTimestamp INT64, +`Properties` JSON, +InternalProperties JSON, +GrantRecordsVersion INT64, +LocationWithoutScheme STRING(MAX)) +PRIMARY KEY (RealmId,Id), +INTERLEAVE IN PARENT Realms ON DELETE CASCADE; + +CREATE UNIQUE NULL_FILTERED INDEX IF NOT EXISTS EntityNameIndex ON Entities(RealmId,CatalogId,ParentId,TypeCode,Name); + +CREATE INDEX IF NOT EXISTS EntityChildrenIndex ON Entities(RealmId,ParentId, TypeCode); +CREATE INDEX IF NOT EXISTS EntityLocationsIndex ON Entities (RealmId, ParentId, LocationWithoutScheme) WHERE LocationWithoutScheme IS NOT NULL; + +CREATE TABLE IF NOT EXISTS GrantRecords( + RealmId STRING(MAX) NOT NULL, + SecurableCatalogId INT64 NOT NULL, + SecurableId INT64 NOT NULL, + GranteeCatalogId INT64 NOT NULL, + GranteeId INT64 NOT NULL, + PrivilegeCode INT64) +PRIMARY KEY (RealmId,SecurableCatalogId,SecurableId,GranteeCatalogId,GranteeId,PrivilegeCode), +INTERLEAVE IN PARENT Realms ON DELETE CASCADE; + +CREATE INDEX IF NOT EXISTS GrantRecordsGranteeIndex ON GrantRecords(RealmId,GranteeCatalogId,GranteeId); + +CREATE TABLE IF NOT EXISTS PrincipalAuthenticationData( + RealmId STRING(MAX) NOT NULL, + PrincipalClientId STRING(MAX) NOT NULL, + PrincipalId INT64 NOT NULL, + MainSecretHash STRING(MAX) NOT NULL, + SecondarySecretHash STRING(MAX) NOT NULL, + SecretSalt STRING(MAX) NOT NULL) +PRIMARY KEY (RealmId,PrincipalClientId,PrincipalId), +INTERLEAVE IN PARENT Realms ON DELETE CASCADE; + + +CREATE TABLE IF NOT EXISTS PolicyMapping( + RealmId STRING(MAX) NOT NULL, + TargetCatalogId INT64 NOT NULL, + TargetId INT64 NOT NULL, + PolicyTypeCode INT64 NOT NULL, + PolicyCatalogId INT64 NOT NULL, + PolicyId INT64 NOT NULL, + Parameters JSON) +PRIMARY KEY (RealmId, TargetCatalogId, TargetId, PolicyTypeCode, PolicyCatalogId, PolicyId), +INTERLEAVE IN PARENT Realms ON DELETE CASCADE; + +CREATE INDEX IF NOT EXISTS PolicyMappingPolicyIndex ON PolicyMapping(RealmId,PolicyCatalogId,PolicyId,PolicyTypeCode) STORING(Parameters); \ No newline at end of file diff --git a/polaris-core/build.gradle.kts b/polaris-core/build.gradle.kts index b8beb85b19..1abbe08305 100644 --- a/polaris-core/build.gradle.kts +++ b/polaris-core/build.gradle.kts @@ -67,9 +67,9 @@ dependencies { implementation("com.azure:azure-storage-file-datalake") implementation("org.apache.iceberg:iceberg-gcp") - implementation(platform(libs.google.cloud.storage.bom)) + implementation(platform(libs.google.cloud.libraries.bom)) implementation("com.google.cloud:google-cloud-storage") - implementation(libs.google.cloud.iamcredentials) + implementation("com.google.cloud:google-cloud-iamcredentials") testCompileOnly(project(":polaris-immutables")) testAnnotationProcessor(project(":polaris-immutables", configuration = "processor")) diff --git a/runtime/service/build.gradle.kts b/runtime/service/build.gradle.kts index 9dcd8c5885..7508c21adb 100644 --- a/runtime/service/build.gradle.kts +++ b/runtime/service/build.gradle.kts @@ -81,7 +81,7 @@ dependencies { compileOnly(libs.jakarta.annotation.api) - implementation(platform(libs.google.cloud.storage.bom)) + implementation(platform(libs.google.cloud.libraries.bom)) implementation("com.google.cloud:google-cloud-storage") implementation(platform(libs.awssdk.bom)) implementation("software.amazon.awssdk:sts") @@ -172,7 +172,7 @@ dependencies { testFixturesImplementation("org.apache.iceberg:iceberg-core") testFixturesImplementation("org.apache.iceberg:iceberg-aws") - testFixturesImplementation(platform(libs.google.cloud.storage.bom)) + testFixturesImplementation(platform(libs.google.cloud.libraries.bom)) testFixturesImplementation("com.google.cloud:google-cloud-storage") testFixturesImplementation(platform(libs.awssdk.bom)) testFixturesImplementation("software.amazon.awssdk:sts")