Skip to content

Commit b5baf4c

Browse files
fix: allow at most one dot in Spanner table names for named schemas (#4418)
Spanner should allow to specify only one dot and it should have text before and after in a table name to support named schemas. Fixes #4384
1 parent a335a2b commit b5baf4c

2 files changed

Lines changed: 86 additions & 5 deletions

File tree

spring-cloud-gcp-data-spanner/src/main/java/com/google/cloud/spring/data/spanner/core/mapping/SpannerPersistentEntityImpl.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public class SpannerPersistentEntityImpl<T>
6262

6363
private static final ExpressionParser PARSER = new SpelExpressionParser();
6464

65-
private static final Pattern TABLE_NAME_ILLEGAL_CHAR_PATTERN = Pattern.compile("[^a-zA-Z0-9_]");
65+
private static final Pattern VALID_TABLE_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+)?$");
6666

6767
private final Class rawType;
6868

@@ -376,9 +376,10 @@ public boolean hasMultiFieldKey() {
376376
// Because SpEL expressions in table name definitions are allowed, validation is
377377
// required.
378378
private String validateTableName(String name) {
379-
if (TABLE_NAME_ILLEGAL_CHAR_PATTERN.matcher(name).find()) {
379+
if (!VALID_TABLE_NAME_PATTERN.matcher(name).matches()) {
380380
throw new SpannerDataException(
381-
"Only letters, numbers, and underscores are " + "allowed in table names: " + name);
381+
"Only letters, numbers, and underscores are allowed in table names, and at most one dot: "
382+
+ name);
382383
}
383384
return name;
384385
}

spring-cloud-gcp-data-spanner/src/test/java/com/google/cloud/spring/data/spanner/core/mapping/SpannerPersistentEntityImplTests.java

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,63 @@ void testInvalidTableName() {
245245
.isInstanceOf(SpannerDataException.class)
246246
.hasMessage("Error getting table name for EntityBadName")
247247
.hasStackTraceContaining(
248-
"Only letters, numbers, and underscores are allowed in table names: ;DROP TABLE your_table;");
248+
"Only letters, numbers, and underscores are allowed in table names, and at most one dot: ;DROP TABLE your_table;");
249+
}
250+
251+
@Test
252+
void testValidTableNameWithDot() {
253+
SpannerPersistentEntityImpl<EntityWithValidDotName> entity =
254+
new SpannerPersistentEntityImpl<>(
255+
TypeInformation.of(EntityWithValidDotName.class),
256+
this.spannerMappingContext,
257+
this.spannerEntityProcessor);
258+
259+
assertThat(entity.tableName()).isEqualTo("schema.table");
260+
}
261+
262+
@Test
263+
void testInvalidTableNameWithDotAtStart() {
264+
SpannerPersistentEntityImpl<EntityWithDotAtStart> entity =
265+
new SpannerPersistentEntityImpl<>(
266+
TypeInformation.of(EntityWithDotAtStart.class),
267+
this.spannerMappingContext,
268+
this.spannerEntityProcessor);
269+
270+
assertThatThrownBy(entity::tableName)
271+
.isInstanceOf(SpannerDataException.class)
272+
.hasMessage("Error getting table name for EntityWithDotAtStart")
273+
.hasStackTraceContaining(
274+
"Only letters, numbers, and underscores are allowed in table names, and at most one dot: .table");
275+
}
276+
277+
@Test
278+
void testInvalidTableNameWithDotAtEnd() {
279+
SpannerPersistentEntityImpl<EntityWithDotAtEnd> entity =
280+
new SpannerPersistentEntityImpl<>(
281+
TypeInformation.of(EntityWithDotAtEnd.class),
282+
this.spannerMappingContext,
283+
this.spannerEntityProcessor);
284+
285+
assertThatThrownBy(entity::tableName)
286+
.isInstanceOf(SpannerDataException.class)
287+
.hasMessage("Error getting table name for EntityWithDotAtEnd")
288+
.hasStackTraceContaining(
289+
"Only letters, numbers, and underscores are allowed in table names, and at most one dot: table.");
290+
}
291+
292+
@Test
293+
void testInvalidTableNameWithMultipleDots() {
294+
SpannerPersistentEntityImpl<EntityWithMultipleDots> entity =
295+
new SpannerPersistentEntityImpl<>(
296+
TypeInformation.of(EntityWithMultipleDots.class),
297+
this.spannerMappingContext,
298+
this.spannerEntityProcessor);
299+
300+
assertThatThrownBy(entity::tableName)
301+
.isInstanceOf(SpannerDataException.class)
302+
.hasMessage("Error getting table name for EntityWithMultipleDots")
303+
.hasStackTraceContaining(
304+
"Only letters, numbers, and underscores are allowed in table names, and at most one dot: schema.table.subtable");
249305
}
250306

251307
@Test
@@ -267,7 +323,7 @@ void testSpelInvalidName() {
267323
.isInstanceOf(SpannerDataException.class)
268324
.hasMessage("Error getting table name for EntityWithExpression")
269325
.hasStackTraceContaining(
270-
"Only letters, numbers, and underscores are allowed in table names: "
326+
"Only letters, numbers, and underscores are allowed in table names, and at most one dot: "
271327
+ "table_; DROP TABLE your_table;");
272328
}
273329

@@ -475,6 +531,30 @@ private static class EntityBadName {
475531
String something;
476532
}
477533

534+
@Table(name = "schema.table")
535+
private static class EntityWithValidDotName {
536+
@PrimaryKey(keyOrder = 1)
537+
String id;
538+
}
539+
540+
@Table(name = ".table")
541+
private static class EntityWithDotAtStart {
542+
@PrimaryKey(keyOrder = 1)
543+
String id;
544+
}
545+
546+
@Table(name = "table.")
547+
private static class EntityWithDotAtEnd {
548+
@PrimaryKey(keyOrder = 1)
549+
String id;
550+
}
551+
552+
@Table(name = "schema.table.subtable")
553+
private static class EntityWithMultipleDots {
554+
@PrimaryKey(keyOrder = 1)
555+
String id;
556+
}
557+
478558
@Table(name = "custom_test_table")
479559
private static class TestEntity {
480560
@PrimaryKey(keyOrder = 1)

0 commit comments

Comments
 (0)