• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yuu-nkjm / sorm4j / #541

14 Mar 2025 03:51AM UTC coverage: 94.924% (-0.2%) from 95.138%
#541

push

yuu-nkjm
Add tests

820 of 920 branches covered (89.13%)

Branch coverage included in aggregate %.

5 of 5 new or added lines in 2 files covered. (100.0%)

28 existing lines in 13 files now uncovered.

4210 of 4379 relevant lines covered (96.14%)

0.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.44
/sorm4j/src/main/java/org/nkjmlab/sorm4j/internal/sql/metadata/jdbc/JdbcDatabaseMetaDataImpl.java
1
package org.nkjmlab.sorm4j.internal.sql.metadata.jdbc;
2

3
import java.sql.DatabaseMetaData;
4
import java.sql.ResultSet;
5
import java.sql.SQLException;
6
import java.util.ArrayList;
7
import java.util.HashMap;
8
import java.util.LinkedHashMap;
9
import java.util.List;
10
import java.util.Map;
11
import java.util.Map.Entry;
12
import java.util.stream.Collectors;
13

14
import org.nkjmlab.sorm4j.sql.metadata.jdbc.JdbcColumnMetaData;
15
import org.nkjmlab.sorm4j.sql.metadata.jdbc.JdbcDatabaseMetaData;
16
import org.nkjmlab.sorm4j.sql.metadata.jdbc.JdbcForeignKeyMetaData;
17
import org.nkjmlab.sorm4j.sql.metadata.jdbc.JdbcIndexMetaData;
18
import org.nkjmlab.sorm4j.sql.metadata.jdbc.JdbcTableMetaData;
19

20
public final class JdbcDatabaseMetaDataImpl implements JdbcDatabaseMetaData {
21

22
  private final String databaseProductName;
23
  private final String databaseProductVersion;
24
  private final String driverName;
25
  private final String driverVersion;
26
  private final String url;
27
  private final String userName;
28

29
  private final int jdbcMajorVersion;
30
  private final int jdbcMinorVersion;
31

32
  private final int defaultTransactionIsolation;
33
  private final int maxConnections;
34
  private final String searchStringEscape;
35

36
  private final String sqlKeywords;
37
  private final String numericFunctions;
38
  private final String stringFunctions;
39
  private final String systemFunctions;
40
  private final String timeDateFunctions;
41

42
  private final boolean supportsTransactions;
43
  private final boolean supportsBatchUpdates;
44
  private final boolean supportsStoredProcedures;
45

46
  private final Map<TableName, JdbcTableMetaData> jdbcTablesMetaData;
47
  private final Map<TableName, Map<String, JdbcIndexMetaData>> jdbcIndexesMetaData;
48
  private final Map<TableName, List<JdbcColumnMetaData>> columnsMetaData;
49
  private final List<TableName> tableNames;
50

51
  private final Map<String, String> schemasMetaData;
52
  private final Map<TableName, List<String>> primaryKeysMetaData;
53
  private final Map<TableName, List<JdbcForeignKeyMetaData>> foreignKeysMetaData;
54

55
  public JdbcDatabaseMetaDataImpl(
56
      String databaseProductName,
57
      String databaseProductVersion,
58
      String driverName,
59
      String driverVersion,
60
      int jdbcMajorVersion,
61
      int jdbcMinorVersion,
62
      int defaultTransactionIsolation,
63
      int maxConnections,
64
      String url,
65
      String userName,
66
      String searchStringEscape,
67
      String sqlKeywords,
68
      String numericFunctions,
69
      String stringFunctions,
70
      String systemFunctions,
71
      String timeDateFunctions,
72
      boolean supportsTransactions,
73
      boolean supportsBatchUpdates,
74
      boolean supportsStoredProcedures,
75
      Map<String, String> schemasMetaData,
76
      Map<TableName, List<String>> primaryKeysMetaData,
77
      Map<TableName, List<JdbcForeignKeyMetaData>> foreignKeysMetaData,
78
      Map<TableName, JdbcTableMetaData> tablesMetaData,
79
      Map<TableName, Map<String, JdbcIndexMetaData>> indexesMetaData,
80
      Map<TableName, List<JdbcColumnMetaData>> columnsMetaData) {
1✔
81
    this.databaseProductName = databaseProductName;
1✔
82
    this.databaseProductVersion = databaseProductVersion;
1✔
83
    this.driverName = driverName;
1✔
84
    this.driverVersion = driverVersion;
1✔
85
    this.jdbcMajorVersion = jdbcMajorVersion;
1✔
86
    this.jdbcMinorVersion = jdbcMinorVersion;
1✔
87
    this.defaultTransactionIsolation = defaultTransactionIsolation;
1✔
88
    this.maxConnections = maxConnections;
1✔
89
    this.url = url;
1✔
90
    this.userName = userName;
1✔
91
    this.searchStringEscape = searchStringEscape;
1✔
92

93
    this.sqlKeywords = sqlKeywords;
1✔
94
    this.numericFunctions = numericFunctions;
1✔
95
    this.stringFunctions = stringFunctions;
1✔
96
    this.systemFunctions = systemFunctions;
1✔
97
    this.timeDateFunctions = timeDateFunctions;
1✔
98

99
    this.supportsTransactions = supportsTransactions;
1✔
100
    this.supportsBatchUpdates = supportsBatchUpdates;
1✔
101
    this.supportsStoredProcedures = supportsStoredProcedures;
1✔
102

103
    this.jdbcTablesMetaData = tablesMetaData;
1✔
104
    this.jdbcIndexesMetaData = indexesMetaData;
1✔
105
    this.columnsMetaData = columnsMetaData;
1✔
106
    this.schemasMetaData = schemasMetaData;
1✔
107
    this.primaryKeysMetaData = primaryKeysMetaData;
1✔
108
    this.foreignKeysMetaData = foreignKeysMetaData;
1✔
109

110
    this.tableNames = tablesMetaData.keySet().stream().collect(Collectors.toList());
1✔
111
  }
1✔
112

113
  @Override
114
  public Map<TableName, List<JdbcColumnMetaData>> getJdbcColumnsMetaData() {
115
    return columnsMetaData;
1✔
116
  }
117

118
  @Override
119
  public String getSqlKeywords() {
120
    return sqlKeywords;
1✔
121
  }
122

123
  @Override
124
  public String getNumericFunctions() {
125
    return numericFunctions;
1✔
126
  }
127

128
  @Override
129
  public String getStringFunctions() {
130
    return stringFunctions;
1✔
131
  }
132

133
  @Override
134
  public String getSystemFunctions() {
135
    return systemFunctions;
1✔
136
  }
137

138
  @Override
139
  public String getTimeDateFunctions() {
140
    return timeDateFunctions;
1✔
141
  }
142

143
  @Override
144
  public boolean isSupportsTransactions() {
145
    return supportsTransactions;
1✔
146
  }
147

148
  @Override
149
  public boolean isSupportsBatchUpdates() {
150
    return supportsBatchUpdates;
1✔
151
  }
152

153
  @Override
154
  public boolean isSupportsStoredProcedures() {
155
    return supportsStoredProcedures;
1✔
156
  }
157

158
  @Override
159
  public Map<String, String> getSchemasMetaData() {
160
    return schemasMetaData;
1✔
161
  }
162

163
  @Override
164
  public Map<TableName, List<String>> getPrimaryKeysMetaData() {
165
    return primaryKeysMetaData;
1✔
166
  }
167

168
  @Override
169
  public Map<TableName, List<JdbcForeignKeyMetaData>> getJdbcForeignKeysMetaData() {
170
    return foreignKeysMetaData;
1✔
171
  }
172

173
  @Override
174
  public String getDatabaseProductName() {
175
    return databaseProductName;
1✔
176
  }
177

178
  @Override
179
  public String getDatabaseProductVersion() {
180
    return databaseProductVersion;
1✔
181
  }
182

183
  @Override
184
  public String getDriverName() {
185
    return driverName;
1✔
186
  }
187

188
  @Override
189
  public String getDriverVersion() {
190
    return driverVersion;
1✔
191
  }
192

193
  @Override
194
  public int getJdbcMajorVersion() {
195
    return jdbcMajorVersion;
1✔
196
  }
197

198
  @Override
199
  public int getJdbcMinorVersion() {
200
    return jdbcMinorVersion;
1✔
201
  }
202

203
  @Override
204
  public String getSearchStringEscape() {
205
    return searchStringEscape;
1✔
206
  }
207

208
  @Override
209
  public String getUrl() {
210
    return url;
1✔
211
  }
212

213
  @Override
214
  public String getUserName() {
215
    return userName;
1✔
216
  }
217

218
  @Override
219
  public int getDefaultTransactionIsolation() {
220
    return defaultTransactionIsolation;
1✔
221
  }
222

223
  @Override
224
  public int getMaxConnections() {
225
    return maxConnections;
1✔
226
  }
227

228
  @Override
229
  public Map<TableName, JdbcTableMetaData> getJdbcTablesMetaData() {
230
    return jdbcTablesMetaData;
1✔
231
  }
232

233
  @Override
234
  public Map<TableName, Map<String, JdbcIndexMetaData>> getJdbcIndexesMetaData() {
235
    return jdbcIndexesMetaData;
1✔
236
  }
237

238
  @Override
239
  public List<TableName> getTableNames() {
240
    return tableNames;
1✔
241
  }
242

243
  @Override
244
  public String toString() {
245
    return "JdbcDatabaseMetaData [databaseProductName="
1✔
246
        + databaseProductName
247
        + ", databaseProductVersion="
248
        + databaseProductVersion
249
        + ", driverName="
250
        + driverName
251
        + ", driverVersion="
252
        + driverVersion
253
        + ", url="
254
        + url
255
        + ", userName="
256
        + userName
257
        + ", driverVersion="
258
        + driverVersion
259
        + ", jdbcMajorVersion="
260
        + jdbcMajorVersion
261
        + ", jdbcMinorVersion="
262
        + jdbcMinorVersion
263
        + ", defaultTransactionIsolation="
264
        + defaultTransactionIsolation
265
        + ", maxConnections="
266
        + maxConnections
267
        + ", searchStringEscape="
268
        + searchStringEscape
269
        + ", sqlKeywords="
270
        + sqlKeywords
271
        + ", numericFunctions="
272
        + numericFunctions
273
        + ", stringFunctions="
274
        + stringFunctions
275
        + ", systemFunctions="
276
        + systemFunctions
277
        + ", timeDateFunctions="
278
        + timeDateFunctions
279
        + ", supportsTransactions="
280
        + supportsTransactions
281
        + ", supportsBatchUpdates="
282
        + supportsBatchUpdates
283
        + ", supportsStoredProcedures="
284
        + supportsStoredProcedures
285
        + ", jdbcTablesMetaData="
286
        + jdbcTablesMetaData
287
        + ", jdbcIndexesMetaData="
288
        + jdbcIndexesMetaData
289
        + ", columnsMetaData="
290
        + columnsMetaData
291
        + ", tableNames="
292
        + tableNames
293
        + ", schemasMetaData="
294
        + schemasMetaData
295
        + ", primaryKeysMetaData="
296
        + primaryKeysMetaData
297
        + ", foreignKeysMetaData="
298
        + foreignKeysMetaData
299
        + "]";
300
  }
301

302
  public static JdbcDatabaseMetaData of(DatabaseMetaData metaData) throws SQLException {
303
    try (ResultSet resultSet =
1✔
304
        metaData.getTables(null, "PUBLIC", null, new String[] {"TABLE", "VIEW"})) {
1✔
305

306
      Map<TableName, JdbcTableMetaData> tables =
1✔
307
          mapColumnsInResultSetToMap(
1✔
308
                  resultSet,
309
                  List.of(
1✔
310
                      "TABLE_CAT",
311
                      "TABLE_SCHEM",
312
                      "TABLE_NAME",
313
                      "TABLE_TYPE",
314
                      "REMARKS",
315
                      "TYPE_CAT",
316
                      "TYPE_SCHEM",
317
                      "TYPE_NAME",
318
                      "SELF_REFERENCING_COL_NAME",
319
                      "REF_GENERATION"))
320
              .stream()
1✔
321
              .map(e -> new JdbcTableMetaDataImpl(e))
1✔
322
              .collect(
1✔
323
                  Collectors.toMap(m -> TableName.of(m.getTableName()), m -> m, (v1, v2) -> v1));
1✔
324

325
      Map<TableName, List<JdbcColumnMetaData>> columns = new HashMap<>();
1✔
326
      Map<TableName, Map<String, JdbcIndexMetaData>> indexes = new HashMap<>();
1✔
327
      for (Entry<TableName, JdbcTableMetaData> jdbcTableEntry : tables.entrySet()) {
1✔
328
        TableName tableName = jdbcTableEntry.getKey();
1✔
329

330
        columns.put(tableName, getColumnsMetaData(metaData, tableName.getName()));
1✔
331

332
        try (ResultSet indexInfo =
1✔
333
            metaData.getIndexInfo(null, null, tableName.getName(), false, false)) {
1✔
334
          Map<String, JdbcIndexMetaData> l =
1✔
335
              mapColumnsInResultSetToMap(
1✔
336
                      indexInfo,
337
                      List.of(
1✔
338
                          "TABLE_CAT",
339
                          "TABLE_SCHEM",
340
                          "TABLE_NAME",
341
                          "NON_UNIQUE",
342
                          "INDEX_QUALIFIER",
343
                          "INDEX_NAME",
344
                          "TYPE",
345
                          "ORDINAL_POSITION",
346
                          "COLUMN_NAME",
347
                          "ASC_OR_DESC",
348
                          "CARDINALITY",
349
                          "PAGES",
350
                          "FILTER_CONDITION"))
351
                  .stream()
1✔
352
                  .map(e -> new JdbcIndexMetaDataImpl(e))
1✔
353
                  .collect(Collectors.toMap(m -> m.getIndexName(), m -> m, (v1, v2) -> v1));
1✔
354
          indexes.put(tableName, l);
1✔
355
        }
356
      }
1✔
357

358
      return new JdbcDatabaseMetaDataImpl(
1✔
359
          metaData.getDatabaseProductName(),
1✔
360
          metaData.getDatabaseProductVersion(),
1✔
361
          metaData.getDriverName(),
1✔
362
          metaData.getDriverVersion(),
1✔
363
          metaData.getJDBCMajorVersion(),
1✔
364
          metaData.getJDBCMinorVersion(),
1✔
365
          metaData.getDefaultTransactionIsolation(),
1✔
366
          metaData.getMaxConnections(),
1✔
367
          metaData.getURL(),
1✔
368
          metaData.getUserName(),
1✔
369
          metaData.getSearchStringEscape(),
1✔
370
          metaData.getSQLKeywords(),
1✔
371
          metaData.getNumericFunctions(),
1✔
372
          metaData.getStringFunctions(),
1✔
373
          metaData.getSystemFunctions(),
1✔
374
          metaData.getTimeDateFunctions(),
1✔
375
          metaData.supportsTransactions(),
1✔
376
          metaData.supportsBatchUpdates(),
1✔
377
          metaData.supportsStoredProcedures(),
1✔
378
          mapSchemas(metaData.getSchemas()),
1✔
379
          mapPrimaryKeys(metaData),
1✔
380
          mapForeignKeys(metaData),
1✔
381
          tables,
382
          indexes,
383
          columns);
384
    }
385
  }
386

387
  private static Map<String, String> mapSchemas(ResultSet schemas) throws SQLException {
388
    Map<String, String> schemaMap = new HashMap<>();
1✔
389
    while (schemas.next()) {
1✔
390
      String schemaName = schemas.getString("TABLE_SCHEM");
1✔
391
      String catalogName = schemas.getString("TABLE_CATALOG");
1✔
392
      schemaMap.put(schemaName, catalogName);
1✔
393
    }
1✔
394
    return schemaMap;
1✔
395
  }
396

397
  private static Map<TableName, List<String>> mapPrimaryKeys(DatabaseMetaData metaData)
398
      throws SQLException {
399
    Map<TableName, List<String>> primaryKeys = new HashMap<>();
1✔
400
    ResultSet pkResultSet = metaData.getTables(null, null, "%", new String[] {"TABLE"});
1✔
401

402
    while (pkResultSet.next()) {
1✔
403
      String tableName = pkResultSet.getString("TABLE_NAME");
1✔
404
      List<String> pkColumns = new ArrayList<>();
1✔
405

406
      try (ResultSet pkColumnsResultSet = metaData.getPrimaryKeys(null, null, tableName)) {
1✔
407
        while (pkColumnsResultSet.next()) {
1✔
408
          pkColumns.add(pkColumnsResultSet.getString("COLUMN_NAME"));
1✔
409
        }
410
      }
411
      primaryKeys.put(TableName.of(tableName), pkColumns);
1✔
412
    }
1✔
413
    return primaryKeys;
1✔
414
  }
415

416
  private static Map<TableName, List<JdbcForeignKeyMetaData>> mapForeignKeys(
417
      DatabaseMetaData metaData) throws SQLException {
418
    Map<TableName, List<JdbcForeignKeyMetaData>> foreignKeys = new HashMap<>();
1✔
419
    ResultSet tablesResultSet = metaData.getTables(null, null, "%", new String[] {"TABLE"});
1✔
420

421
    while (tablesResultSet.next()) {
1✔
422
      String tableName = tablesResultSet.getString("TABLE_NAME");
1✔
423
      List<JdbcForeignKeyMetaData> fkList = new ArrayList<>();
1✔
424

425
      try (ResultSet fkResultSet = metaData.getImportedKeys(null, null, tableName)) {
1✔
426
        while (fkResultSet.next()) {
1✔
427
          fkList.add(
1✔
428
              new JdbcForeignKeyMetaDataImpl(
429
                  fkResultSet.getString("FKTABLE_NAME"),
1✔
430
                  fkResultSet.getString("FKCOLUMN_NAME"),
1✔
431
                  fkResultSet.getString("PKTABLE_NAME"),
1✔
432
                  fkResultSet.getString("PKCOLUMN_NAME"),
1✔
433
                  fkResultSet.getShort("UPDATE_RULE"),
1✔
434
                  fkResultSet.getShort("DELETE_RULE")));
1✔
435
        }
436
      }
437
      foreignKeys.put(TableName.of(tableName), fkList);
1✔
438
    }
1✔
439
    return foreignKeys;
1✔
440
  }
441

442
  private static List<Map<String, Object>> mapColumnsInResultSetToMap(
443
      ResultSet resultSet, List<String> columns) throws SQLException {
444
    List<Map<String, Object>> result = new ArrayList<>();
1✔
445

446
    while (resultSet.next()) {
1✔
447
      Map<String, Object> tmp = new LinkedHashMap<>();
1✔
448
      columns.forEach(
1✔
449
          col -> {
450
            try {
451
              tmp.put(col, resultSet.getObject(col));
1✔
UNCOV
452
            } catch (SQLException e) {
×
453
              tmp.put(col, null);
×
454
            }
1✔
455
          });
1✔
456

457
      result.add(tmp);
1✔
458
    }
1✔
459
    return result;
1✔
460
  }
461

462
  private static String getSchemaPattern(DatabaseMetaData metaData) throws SQLException {
463
    // oracle expects a pattern such as "%" to work
464
    return "Oracle".equalsIgnoreCase(metaData.getDatabaseProductName()) ? "%" : null;
1!
465
  }
466

467
  public static List<JdbcColumnMetaData> getColumnsMetaData(
468
      DatabaseMetaData metaData, String _tableName) throws SQLException {
469
    try (ResultSet resultSet =
1✔
470
        metaData.getColumns(null, getSchemaPattern(metaData), _tableName, "%")) {
1✔
471
      final List<JdbcColumnMetaData> columnsList = new ArrayList<>();
1✔
472
      while (resultSet.next()) {
1✔
473
        String tableCatalog = resultSet.getString(1);
1✔
474
        String tableSchema = resultSet.getString(2);
1✔
475
        String tableName = resultSet.getString(3);
1✔
476
        String columnName = resultSet.getString(4);
1✔
477
        int dataType = resultSet.getInt(5);
1✔
478
        String typeName = resultSet.getString(6);
1✔
479
        int columnSize = resultSet.getInt(7);
1✔
480
        int decimalDigits = resultSet.getInt(9);
1✔
481
        int numPrecRadix = resultSet.getInt(10);
1✔
482
        int nullableFlag = resultSet.getInt(11);
1✔
483
        String remarks = resultSet.getString(12);
1✔
484
        String columnDefault = resultSet.getString(13);
1✔
485
        int charOctetLength = resultSet.getInt(16);
1✔
486
        int ordinalPosition = resultSet.getInt(17);
1✔
487
        String isNullable = resultSet.getString(18);
1✔
488
        String isAutoIncremented = resultSet.getString(23);
1✔
489
        String isGenerated = resultSet.getString(24);
1✔
490

491
        columnsList.add(
1✔
492
            new JdbcColumnMetaDataImpl(
493
                tableCatalog,
494
                tableSchema,
495
                tableName,
496
                columnName,
497
                dataType,
498
                typeName,
499
                columnSize,
500
                numPrecRadix,
501
                decimalDigits,
502
                ordinalPosition,
503
                nullableFlag,
504
                charOctetLength,
505
                isNullable,
506
                columnDefault,
507
                remarks,
508
                isAutoIncremented,
509
                isGenerated));
510
      }
1✔
511
      return columnsList;
1✔
512
    }
513
  }
514
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc