Skip to content

Commit 98eb542

Browse files
authoredFeb 27, 2025··
fix: include COLUMN_DEFAULT in the returned metadata (#1937)
Include the COLUMN_DEFAULT value in the DatabaseMetaData that is returned for the getColumns() method. These were missing, as Spanner previously did not support default values.
1 parent c30b09a commit 98eb542

File tree

4 files changed

+112
-32
lines changed

4 files changed

+112
-32
lines changed
 

‎src/main/resources/com/google/cloud/spanner/jdbc/DatabaseMetaData_GetColumns.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA AS TABLE_SCHEM, TABLE_NAME, COLU
6363
ELSE 2
6464
END AS NULLABLE,
6565
NULL AS REMARKS,
66-
NULL AS COLUMN_DEF,
66+
COLUMN_DEFAULT AS COLUMN_DEF,
6767
0 AS SQL_DATA_TYPE,
6868
0 AS SQL_DATETIME_SUB,
6969
CASE

‎src/main/resources/com/google/cloud/spanner/jdbc/postgresql/DatabaseMetaData_GetColumns.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ SELECT TABLE_CATALOG AS "TABLE_CAT", TABLE_SCHEMA AS "TABLE_SCHEM", TABLE_NAME A
6262
ELSE 2
6363
END AS "NULLABLE",
6464
NULL AS "REMARKS",
65-
NULL AS "COLUMN_DEF",
65+
COLUMN_DEFAULT AS "COLUMN_DEF",
6666
0 AS "SQL_DATA_TYPE",
6767
0 AS "SQL_DATETIME_SUB",
6868
CHARACTER_MAXIMUM_LENGTH AS "CHAR_OCTET_LENGTH",

‎src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcDatabaseMetaDataTest.java

+105-25
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import static org.junit.Assert.assertNotNull;
2222
import static org.junit.Assert.assertNull;
2323
import static org.junit.Assert.assertTrue;
24-
import static org.junit.Assume.assumeFalse;
2524

2625
import com.google.cloud.spanner.Database;
2726
import com.google.cloud.spanner.DatabaseAdminClient;
@@ -62,10 +61,6 @@ public class ITJdbcDatabaseMetaDataTest extends ITAbstractJdbcTest {
6261

6362
@BeforeClass
6463
public static void setup() throws Exception {
65-
assumeFalse(
66-
"Named schemas are not yet supported on the emulator",
67-
EmulatorSpannerHelper.isUsingEmulator());
68-
6964
database =
7065
env.getOrCreateDatabase(
7166
Dialect.GOOGLE_STANDARD_SQL, getMusicTablesDdl(Dialect.GOOGLE_STANDARD_SQL));
@@ -89,6 +84,18 @@ public static void setup() throws Exception {
8984
.map(statement -> statement.replace(" ON ", " ON test."))
9085
.map(statement -> statement.replace(" ON test.DELETE", " ON DELETE"))
9186
.map(statement -> statement.replace(" REFERENCES ", " REFERENCES test."))
87+
.map(
88+
statement ->
89+
EmulatorSpannerHelper.isUsingEmulator()
90+
? statement.replace("Fk_Concerts_Singer", "test_Fk_Concerts_Singer")
91+
: statement)
92+
.map(
93+
statement ->
94+
EmulatorSpannerHelper.isUsingEmulator()
95+
? statement.replace(
96+
"Fk_TableWithRef_TableWithAllColumnTypes",
97+
"test_Fk_TableWithRef_TableWithAllColumnTypes")
98+
: statement)
9299
.collect(Collectors.toList());
93100
tables.add(0, "create schema test");
94101
client
@@ -110,6 +117,7 @@ private static final class Column {
110117
private final boolean nullable;
111118
private final Integer charOctetLength;
112119
private final boolean computed;
120+
private final String defaultValue;
113121

114122
private Column(
115123
String name,
@@ -120,7 +128,17 @@ private Column(
120128
Integer radix,
121129
boolean nullable,
122130
Integer charOctetLength) {
123-
this(name, type, typeName, colSize, decimalDigits, radix, nullable, charOctetLength, false);
131+
this(
132+
name,
133+
type,
134+
typeName,
135+
colSize,
136+
decimalDigits,
137+
radix,
138+
nullable,
139+
charOctetLength,
140+
false,
141+
null);
124142
}
125143

126144
private Column(
@@ -132,7 +150,8 @@ private Column(
132150
Integer radix,
133151
boolean nullable,
134152
Integer charOctetLength,
135-
boolean computed) {
153+
boolean computed,
154+
String defaultValue) {
136155
this.name = name;
137156
this.type = type;
138157
this.typeName = typeName;
@@ -142,21 +161,42 @@ private Column(
142161
this.nullable = nullable;
143162
this.charOctetLength = charOctetLength;
144163
this.computed = computed;
164+
this.defaultValue = defaultValue;
145165
}
146166
}
147167

148168
private static final List<Column> EXPECTED_COLUMNS =
149169
Arrays.asList(
150170
new Column("ColInt64", Types.BIGINT, "INT64", 19, null, 10, false, null),
151-
new Column("ColFloat64", Types.DOUBLE, "FLOAT64", 15, 16, 2, false, null),
152-
new Column("ColFloat32", Types.REAL, "FLOAT32", 15, 16, 2, false, null),
171+
new Column("ColFloat64", Types.DOUBLE, "FLOAT64", 15, 16, 2, false, null, false, "0.0"),
172+
new Column("ColFloat32", Types.REAL, "FLOAT32", 15, 16, 2, false, null, false, "0.0"),
153173
new Column("ColBool", Types.BOOLEAN, "BOOL", null, null, null, false, null),
154-
new Column("ColString", Types.NVARCHAR, "STRING(100)", 100, null, null, false, 100),
174+
new Column(
175+
"ColString",
176+
Types.NVARCHAR,
177+
"STRING(100)",
178+
100,
179+
null,
180+
null,
181+
false,
182+
100,
183+
false,
184+
"'Hello World!'"),
155185
new Column(
156186
"ColStringMax", Types.NVARCHAR, "STRING(MAX)", 2621440, null, null, false, 2621440),
157187
new Column("ColBytes", Types.BINARY, "BYTES(100)", 100, null, null, false, null),
158188
new Column("ColBytesMax", Types.BINARY, "BYTES(MAX)", 10485760, null, null, false, null),
159-
new Column("ColDate", Types.DATE, "DATE", 10, null, null, false, null),
189+
new Column(
190+
"ColDate",
191+
Types.DATE,
192+
"DATE",
193+
10,
194+
null,
195+
null,
196+
false,
197+
null,
198+
false,
199+
"DATE '2000-01-01'"),
160200
new Column("ColTimestamp", Types.TIMESTAMP, "TIMESTAMP", 35, null, null, false, null),
161201
new Column("ColCommitTS", Types.TIMESTAMP, "TIMESTAMP", 35, null, null, false, null),
162202
new Column("ColNumeric", Types.NUMERIC, "NUMERIC", 15, null, 10, false, null),
@@ -202,7 +242,8 @@ private Column(
202242
null,
203243
true,
204244
2621440,
205-
true));
245+
true,
246+
null));
206247

207248
@Test
208249
public void testGetColumns() throws SQLException {
@@ -244,7 +285,7 @@ public void testGetColumns() throws SQLException {
244285
col.nullable ? DatabaseMetaData.columnNullable : DatabaseMetaData.columnNoNulls,
245286
rs.getInt("NULLABLE"));
246287
assertNull(rs.getString("REMARKS"));
247-
assertNull(rs.getString("COLUMN_DEF"));
288+
assertEquals(col.defaultValue, rs.getString("COLUMN_DEF"));
248289
assertEquals(0, rs.getInt("SQL_DATA_TYPE"));
249290
assertEquals(0, rs.getInt("SQL_DATETIME_SUB"));
250291
if (col.charOctetLength == null) {
@@ -360,7 +401,11 @@ public void testGetCrossReferences() throws SQLException {
360401
assertEquals(1, rs.getShort("KEY_SEQ"));
361402
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("UPDATE_RULE"));
362403
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("DELETE_RULE"));
363-
assertEquals("Fk_Concerts_Singer", rs.getString("FK_NAME"));
404+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
405+
assertEquals("test_Fk_Concerts_Singer", rs.getString("FK_NAME"));
406+
} else {
407+
assertEquals("Fk_Concerts_Singer", rs.getString("FK_NAME"));
408+
}
364409
assertEquals("PK_Singers", rs.getString("PK_NAME"));
365410
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getShort("DEFERRABILITY"));
366411
assertFalse(rs.next());
@@ -389,7 +434,11 @@ public void testGetCrossReferences() throws SQLException {
389434
assertEquals(1, rs.getShort("KEY_SEQ"));
390435
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("UPDATE_RULE"));
391436
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("DELETE_RULE"));
392-
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
437+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
438+
assertEquals("test_Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
439+
} else {
440+
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
441+
}
393442
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getShort("DEFERRABILITY"));
394443

395444
assertTrue(rs.next());
@@ -404,7 +453,11 @@ public void testGetCrossReferences() throws SQLException {
404453
assertEquals(2, rs.getShort("KEY_SEQ"));
405454
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("UPDATE_RULE"));
406455
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("DELETE_RULE"));
407-
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
456+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
457+
assertEquals("test_Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
458+
} else {
459+
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
460+
}
408461
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getShort("DEFERRABILITY"));
409462

410463
assertTrue(rs.next());
@@ -419,7 +472,11 @@ public void testGetCrossReferences() throws SQLException {
419472
assertEquals(3, rs.getShort("KEY_SEQ"));
420473
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("UPDATE_RULE"));
421474
assertEquals(DatabaseMetaData.importedKeyNoAction, rs.getShort("DELETE_RULE"));
422-
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
475+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
476+
assertEquals("test_Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
477+
} else {
478+
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
479+
}
423480
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getShort("DEFERRABILITY"));
424481

425482
assertFalse(rs.next());
@@ -519,6 +576,12 @@ public void testGetIndexInfo() throws SQLException {
519576
connection.getMetaData().getIndexInfo(DEFAULT_CATALOG, schema, null, false, false)) {
520577

521578
for (IndexInfo index : EXPECTED_INDICES) {
579+
// The emulator does not generate indexes for foreign keys in a non-default schema.
580+
if (EmulatorSpannerHelper.isUsingEmulator()
581+
&& "test".equals(schema)
582+
&& ("FOREIGN_KEY".equals(index.indexName) || "GENERATED".equals(index.indexName))) {
583+
continue;
584+
}
522585
assertTrue(rs.next());
523586
assertEquals(DEFAULT_CATALOG, rs.getString("TABLE_CAT"));
524587
assertEquals(schema, rs.getString("TABLE_SCHEM"));
@@ -612,7 +675,11 @@ private void assertImportedKeysTableWithRef(String schema, ResultSet rs) throws
612675
assertEquals(1, rs.getShort("KEY_SEQ"));
613676
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE"));
614677
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE"));
615-
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
678+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
679+
assertEquals("test_Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
680+
} else {
681+
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
682+
}
616683
assertNotNull(rs.getString("PK_NAME")); // Index name is generated.
617684
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));
618685

@@ -628,7 +695,11 @@ private void assertImportedKeysTableWithRef(String schema, ResultSet rs) throws
628695
assertEquals(2, rs.getShort("KEY_SEQ"));
629696
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE"));
630697
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE"));
631-
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
698+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
699+
assertEquals("test_Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
700+
} else {
701+
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
702+
}
632703
assertNotNull(rs.getString("PK_NAME")); // Index name is generated.
633704
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));
634705

@@ -644,7 +715,11 @@ private void assertImportedKeysTableWithRef(String schema, ResultSet rs) throws
644715
assertEquals(3, rs.getShort("KEY_SEQ"));
645716
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE"));
646717
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE"));
647-
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
718+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
719+
assertEquals("test_Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
720+
} else {
721+
assertEquals("Fk_TableWithRef_TableWithAllColumnTypes", rs.getString("FK_NAME"));
722+
}
648723
assertNotNull(rs.getString("PK_NAME")); // Index name is generated.
649724
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));
650725

@@ -684,7 +759,11 @@ private void assertImportedKeysConcerts(String schema, ResultSet rs) throws SQLE
684759
assertEquals(1, rs.getShort("KEY_SEQ"));
685760
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE"));
686761
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE"));
687-
assertEquals("Fk_Concerts_Singer", rs.getString("FK_NAME"));
762+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
763+
assertEquals("test_Fk_Concerts_Singer", rs.getString("FK_NAME"));
764+
} else {
765+
assertEquals("Fk_Concerts_Singer", rs.getString("FK_NAME"));
766+
}
688767
assertEquals("PK_Singers", rs.getString("PK_NAME"));
689768
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));
690769

@@ -720,7 +799,11 @@ private void assertExportedKeysSingers(String schema, ResultSet rs) throws SQLEx
720799
assertEquals(1, rs.getShort("KEY_SEQ"));
721800
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("UPDATE_RULE"));
722801
assertEquals(DatabaseMetaData.importedKeyRestrict, rs.getInt("DELETE_RULE"));
723-
assertEquals("Fk_Concerts_Singer", rs.getString("FK_NAME"));
802+
if (EmulatorSpannerHelper.isUsingEmulator() && "test".equals(schema)) {
803+
assertEquals("test_Fk_Concerts_Singer", rs.getString("FK_NAME"));
804+
} else {
805+
assertEquals("Fk_Concerts_Singer", rs.getString("FK_NAME"));
806+
}
724807
assertEquals("PK_Singers", rs.getString("PK_NAME"));
725808
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));
726809

@@ -888,9 +971,6 @@ public void testGetTables() throws SQLException {
888971
try (ResultSet rs =
889972
connection.getMetaData().getTables(DEFAULT_CATALOG, schema, null, null)) {
890973
for (Table table : EXPECTED_TABLES) {
891-
if (EmulatorSpannerHelper.isUsingEmulator() && table.name.equals("SingersView")) {
892-
continue;
893-
}
894974
assertTrue(rs.next());
895975
assertEquals(DEFAULT_CATALOG, rs.getString("TABLE_CAT"));
896976
assertEquals(schema, rs.getString("TABLE_SCHEM"));

‎src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql

+5-5
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ CREATE TABLE Songs (
4949
TrackId INT64 NOT NULL,
5050
SongName STRING(MAX),
5151
Duration INT64,
52-
SongGenre STRING(25)
52+
SongGenre STRING(25) DEFAULT ('Jazz')
5353
) PRIMARY KEY(SingerId, AlbumId, TrackId),
5454
INTERLEAVE IN PARENT Albums ON DELETE CASCADE;
5555

@@ -69,14 +69,14 @@ CREATE TABLE Concerts (
6969

7070
CREATE TABLE TableWithAllColumnTypes (
7171
ColInt64 INT64 NOT NULL,
72-
ColFloat64 FLOAT64 NOT NULL,
73-
ColFloat32 FLOAT32 NOT NULL,
72+
ColFloat64 FLOAT64 NOT NULL DEFAULT (0.0),
73+
ColFloat32 FLOAT32 NOT NULL DEFAULT (0.0),
7474
ColBool BOOL NOT NULL,
75-
ColString STRING(100) NOT NULL,
75+
ColString STRING(100) NOT NULL DEFAULT ('Hello World!'),
7676
ColStringMax STRING(MAX) NOT NULL,
7777
ColBytes BYTES(100) NOT NULL,
7878
ColBytesMax BYTES(MAX) NOT NULL,
79-
ColDate DATE NOT NULL,
79+
ColDate DATE NOT NULL DEFAULT (DATE '2000-01-01'),
8080
ColTimestamp TIMESTAMP NOT NULL,
8181
ColCommitTS TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
8282
ColNumeric NUMERIC NOT NULL,

0 commit comments

Comments
 (0)
Please sign in to comment.