diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java index 4fd1c0b67f67..a3b913160172 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java @@ -24,6 +24,8 @@ import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitOffsetLimitHandler; import org.hibernate.dialect.sql.ast.SpannerSqlAstTranslator; +import org.hibernate.dialect.temptable.SpannerTemporaryTableExporter; +import org.hibernate.dialect.temptable.TemporaryTableExporter; import org.hibernate.dialect.unique.UniqueDelegate; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; @@ -99,6 +101,9 @@ public class SpannerDialect extends Dialect { private final Exporter spannerTableExporter = new SpannerDialectTableExporter( this ); + private final SpannerTemporaryTableExporter spannerTemporaryTableExporter = new SpannerTemporaryTableExporter( + this ); + private static final LockingStrategy LOCKING_STRATEGY = new DoNothingLockingStrategy(); private static final EmptyExporter NOOP_EXPORTER = new EmptyExporter(); @@ -720,6 +725,11 @@ public String getAddPrimaryKeyConstraintString(String constraintName) { throw new UnsupportedOperationException( "Cannot add primary key constraint in Cloud Spanner." ); } + @Override + public TemporaryTableExporter getTemporaryTableExporter() { + return spannerTemporaryTableExporter; + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Lock acquisition functions diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/temptable/SpannerTemporaryTableExporter.java b/hibernate-core/src/main/java/org/hibernate/dialect/temptable/SpannerTemporaryTableExporter.java new file mode 100644 index 000000000000..a5b625ea285e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/temptable/SpannerTemporaryTableExporter.java @@ -0,0 +1,78 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.dialect.temptable; + +import org.hibernate.dialect.SpannerDialect; +import org.hibernate.engine.spi.SharedSessionContractImplementor; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +/** + * Spanner-specific exporter for temporary tables. + * Spanner requires PRIMARY KEY definitions to be outside the column definition list. + * * Syntax: CREATE TABLE Name (Col Type) PRIMARY KEY (Col) + */ +public class SpannerTemporaryTableExporter extends StandardTemporaryTableExporter { + + private final SpannerDialect dialect; + + public SpannerTemporaryTableExporter(SpannerDialect dialect) { + super( dialect ); + this.dialect = dialect; + } + + @Override + public String getSqlCreateCommand(TemporaryTable temporaryTable) { + final StringBuilder buffer = new StringBuilder( dialect.getCreateTableString() ) + .append( ' ' ) + .append( temporaryTable.getQualifiedTableName() ) + .append( " (" ); + final List primaryKeyColumnNames = new ArrayList<>(); + boolean first = true; + for ( TemporaryTableColumn column : temporaryTable.getColumnsForExport() ) { + if ( first ) { + first = false; + } + else { + buffer.append( ", " ); + } + buffer.append( column.getColumnName() ).append( ' ' ); + final String databaseTypeName = column.getSqlTypeDefinition(); + buffer.append( databaseTypeName ); + if ( !column.isNullable() ) { + buffer.append( " not null" ); + } + // Track PK + if ( column.isPrimaryKey() ) { + primaryKeyColumnNames.add( column.getColumnName() ); + } + } + buffer.append( ')' ); + // append primary key (outside the column declaration for Spanner) + // primary key () is still needed even if there are no primary key columns + buffer.append( " primary key (" ); + if ( !primaryKeyColumnNames.isEmpty() ) { + buffer.append( String.join( ", ", primaryKeyColumnNames ) ); + } + buffer.append( ')' ); + return buffer.toString(); + } + + @Override + public String getSqlTruncateCommand( + TemporaryTable temporaryTable, + Function sessionUidAccess, + SharedSessionContractImplementor session) { + if ( temporaryTable.getSessionUidColumn() != null ) { + return super.getSqlTruncateCommand( temporaryTable, sessionUidAccess, session ); + } + else { + return dialect.getTruncateTableStatement( temporaryTable.getQualifiedTableName() ); + } + } + +}