Skip to content

Commit

Permalink
chore: add method for getting the backend type name (googleapis#2763)
Browse files Browse the repository at this point in the history
* chore: add method for getting the backend type name

JDBC must be able to return the type name of a query parameter.
Currently, that is done with a custom implementation in the JDBC driver.
This adds a method to the Spanner client for the same, so the feature is
in a more logical place.

* chore: add ignored change to clirr
  • Loading branch information
olavloite authored Dec 26, 2023
1 parent 247946e commit 23ce386
Show file tree
Hide file tree
Showing 5 changed files with 395 additions and 17 deletions.
6 changes: 6 additions & 0 deletions google-cloud-spanner/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -455,4 +455,10 @@
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
<method>java.util.Set getExecuteQueryRetryableCodes()</method>
</difference>
<!-- Added getDefaultSchema() to Dialect enum. -->
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/Dialect</className>
<method>java.lang.String getDefaultSchema()</method>
</difference>
</differences>
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public String createDatabaseStatementFor(String databaseName) {
public DatabaseDialect toProto() {
return DatabaseDialect.GOOGLE_STANDARD_SQL;
}

@Override
public String getDefaultSchema() {
return "";
}
},
POSTGRESQL {
@Override
Expand All @@ -44,6 +49,11 @@ public String createDatabaseStatementFor(String databaseName) {
public DatabaseDialect toProto() {
return DatabaseDialect.POSTGRESQL;
}

@Override
public String getDefaultSchema() {
return "public";
}
};

private static final Map<DatabaseDialect, Dialect> protoToDialect =
Expand All @@ -56,6 +66,8 @@ public DatabaseDialect toProto() {

public abstract DatabaseDialect toProto();

public abstract String getDefaultSchema();

public static Dialect fromProto(DatabaseDialect databaseDialect) {
final Dialect dialect = protoToDialect.get(databaseDialect);
if (dialect == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,20 +234,20 @@ private Type(

/** Enumerates the categories of types. */
public enum Code {
UNRECOGNIZED(TypeCode.UNRECOGNIZED),
BOOL(TypeCode.BOOL),
INT64(TypeCode.INT64),
NUMERIC(TypeCode.NUMERIC),
PG_NUMERIC(TypeCode.NUMERIC, TypeAnnotationCode.PG_NUMERIC),
FLOAT64(TypeCode.FLOAT64),
STRING(TypeCode.STRING),
JSON(TypeCode.JSON),
PG_JSONB(TypeCode.JSON, TypeAnnotationCode.PG_JSONB),
BYTES(TypeCode.BYTES),
TIMESTAMP(TypeCode.TIMESTAMP),
DATE(TypeCode.DATE),
ARRAY(TypeCode.ARRAY),
STRUCT(TypeCode.STRUCT);
UNRECOGNIZED(TypeCode.UNRECOGNIZED, "unknown"),
BOOL(TypeCode.BOOL, "boolean"),
INT64(TypeCode.INT64, "bigint"),
NUMERIC(TypeCode.NUMERIC, "unknown"),
PG_NUMERIC(TypeCode.NUMERIC, "numeric", TypeAnnotationCode.PG_NUMERIC),
FLOAT64(TypeCode.FLOAT64, "double precision"),
STRING(TypeCode.STRING, "character varying"),
JSON(TypeCode.JSON, "unknown"),
PG_JSONB(TypeCode.JSON, "jsonb", TypeAnnotationCode.PG_JSONB),
BYTES(TypeCode.BYTES, "bytea"),
TIMESTAMP(TypeCode.TIMESTAMP, "timestamp with time zone"),
DATE(TypeCode.DATE, "date"),
ARRAY(TypeCode.ARRAY, "array"),
STRUCT(TypeCode.STRUCT, "struct");

private static final Map<Entry<TypeCode, TypeAnnotationCode>, Code> protoToCode;

Expand All @@ -260,15 +260,17 @@ public enum Code {
protoToCode = builder.build();
}

private final String postgreSQLName;
private final TypeCode typeCode;
private final TypeAnnotationCode typeAnnotationCode;

Code(TypeCode typeCode) {
this(typeCode, TYPE_ANNOTATION_CODE_UNSPECIFIED);
Code(TypeCode typeCode, String postgreSQLName) {
this(typeCode, postgreSQLName, TYPE_ANNOTATION_CODE_UNSPECIFIED);
}

Code(TypeCode typeCode, TypeAnnotationCode typeAnnotationCode) {
Code(TypeCode typeCode, String postgreSQLName, TypeAnnotationCode typeAnnotationCode) {
this.typeCode = typeCode;
this.postgreSQLName = postgreSQLName;
this.typeAnnotationCode = typeAnnotationCode;
}

Expand All @@ -293,6 +295,14 @@ public String toString() {
return typeCode.toString() + "<" + typeAnnotationCode.toString() + ">";
}
}

private String getGoogleSQLName() {
return name();
}

private String getPostgreSQLName() {
return postgreSQLName;
}
}

/** Describes an individual field in a {@code STRUCT type}. */
Expand Down Expand Up @@ -439,6 +449,31 @@ public String toString() {
return b.toString();
}

/** Returns the type name as used by the database in the given dialect. */
public String getSpannerTypeName(Dialect dialect) {
switch (dialect) {
case POSTGRESQL:
return getTypeNamePostgreSQL();
case GOOGLE_STANDARD_SQL:
default:
return getTypeNameGoogleSQL();
}
}

private String getTypeNameGoogleSQL() {
if (code == Code.ARRAY) {
return code.getGoogleSQLName() + "<" + arrayElementType.getTypeNameGoogleSQL() + ">";
}
return code.getGoogleSQLName();
}

private String getTypeNamePostgreSQL() {
if (code == Code.ARRAY) {
return arrayElementType.getTypeNamePostgreSQL() + "[]";
}
return code.getPostgreSQLName();
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,69 @@ public void testUnrecognizedArrayWithAnnotation() {
assertNotEquals(unrecognizedArray, Type.array(Type.int64()));
}

@Test
public void testGoogleSQLTypeNames() {
assertEquals("INT64", Type.int64().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("BOOL", Type.bool().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("FLOAT64", Type.float64().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("STRING", Type.string().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("BYTES", Type.bytes().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("DATE", Type.date().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("TIMESTAMP", Type.timestamp().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("JSON", Type.json().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals("NUMERIC", Type.numeric().getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));

assertEquals(
"ARRAY<INT64>", Type.array(Type.int64()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<BOOL>", Type.array(Type.bool()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<FLOAT64>",
Type.array(Type.float64()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<STRING>", Type.array(Type.string()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<BYTES>", Type.array(Type.bytes()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<DATE>", Type.array(Type.date()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<TIMESTAMP>",
Type.array(Type.timestamp()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<JSON>", Type.array(Type.json()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
assertEquals(
"ARRAY<NUMERIC>",
Type.array(Type.numeric()).getSpannerTypeName(Dialect.GOOGLE_STANDARD_SQL));
}

@Test
public void testPostgreSQLTypeNames() {
assertEquals("bigint", Type.int64().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("boolean", Type.bool().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("double precision", Type.float64().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("character varying", Type.string().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("bytea", Type.bytes().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("date", Type.date().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals(
"timestamp with time zone", Type.timestamp().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("jsonb", Type.pgJsonb().getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("numeric", Type.pgNumeric().getSpannerTypeName(Dialect.POSTGRESQL));

assertEquals("bigint[]", Type.array(Type.int64()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("boolean[]", Type.array(Type.bool()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals(
"double precision[]", Type.array(Type.float64()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals(
"character varying[]", Type.array(Type.string()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("bytea[]", Type.array(Type.bytes()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("date[]", Type.array(Type.date()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals(
"timestamp with time zone[]",
Type.array(Type.timestamp()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("jsonb[]", Type.array(Type.pgJsonb()).getSpannerTypeName(Dialect.POSTGRESQL));
assertEquals("numeric[]", Type.array(Type.pgNumeric()).getSpannerTypeName(Dialect.POSTGRESQL));
}

private static void assertProtoEquals(com.google.spanner.v1.Type proto, String expected) {
MatcherAssert.assertThat(
proto, SpannerMatchers.matchesProto(com.google.spanner.v1.Type.class, expected));
Expand Down
Loading

0 comments on commit 23ce386

Please sign in to comment.