Skip to content

Commit a6bcedd

Browse files
committed
DbAdapter refactoring - NativeColumnType with details about specific native column types
1 parent 319e107 commit a6bcedd

22 files changed

Lines changed: 708 additions & 524 deletions

File tree

cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/factory/IngresMergerTokenFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public List<String> createSql(DbAdapter adapter) {
150150
sqlBuffer.append(" ALTER COLUMN ");
151151
sqlBuffer.append(context.quotedName(getColumn()));
152152
sqlBuffer.append(" ");
153-
sqlBuffer.append(adapter.externalTypesForJdbcType(getColumn().getType())[0]);
153+
sqlBuffer.append(adapter.nativeColumnTypes(getColumn().getType())[0].nativeType());
154154

155155
if (adapter.typeSupportsLength(getColumn().getType()) && getColumn().getMaxLength() > 0) {
156156
sqlBuffer.append("(");
@@ -179,7 +179,7 @@ public List<String> createSql(DbAdapter adapter) {
179179
sqlBuffer.append(" ALTER COLUMN ");
180180
sqlBuffer.append(context.quotedName(getColumn()));
181181
sqlBuffer.append(" ");
182-
sqlBuffer.append(adapter.externalTypesForJdbcType(getColumn().getType())[0]);
182+
sqlBuffer.append(adapter.nativeColumnTypes(getColumn().getType())[0].nativeType());
183183

184184
if (adapter.typeSupportsLength(getColumn().getType()) && getColumn().getMaxLength() > 0) {
185185
sqlBuffer.append("(");

cayenne/src/main/java/org/apache/cayenne/dba/AutoAdapter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,17 @@ public String createFkConstraint(DbRelationship rel) {
190190
return getAdapter().createFkConstraint(rel);
191191
}
192192

193+
@Deprecated(since = "5.0", forRemoval = true)
193194
@Override
194195
public String[] externalTypesForJdbcType(int type) {
195196
return getAdapter().externalTypesForJdbcType(type);
196197
}
197198

199+
@Override
200+
public NativeColumnType[] nativeColumnTypes(int type) {
201+
return getAdapter().nativeColumnTypes(type);
202+
}
203+
198204
@Override
199205
public ExtendedTypeMap getExtendedTypes() {
200206
return getAdapter().getExtendedTypes();

cayenne/src/main/java/org/apache/cayenne/dba/DbAdapter.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,20 @@ default boolean supportsGeneratedKeysForBatchInserts() {
162162
/**
163163
* Returns an array of RDBMS types that can be used with JDBC
164164
* <code>type</code>. Valid JDBC types are defined in java.sql.Types.
165+
*
166+
* @deprecated use {@link #nativeColumnTypes(int)}
165167
*/
168+
@Deprecated(since = "5.0", forRemoval = true)
166169
String[] externalTypesForJdbcType(int type);
167170

171+
/**
172+
* Returns the database-native types that the given JDBC <code>type</code> (see {@link java.sql.Types}) maps to,
173+
* or null if the type is not supported. The first variant is used for column DDL.
174+
*
175+
* @since 5.0
176+
*/
177+
NativeColumnType[] nativeColumnTypes(int type);
178+
168179
/**
169180
* Returns a map of ExtendedTypes that is used to translate values between
170181
* Java and JDBC layer.

cayenne/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050

5151
import java.sql.PreparedStatement;
5252
import java.sql.Types;
53+
import java.util.ArrayList;
5354
import java.util.Collection;
5455
import java.util.Collections;
5556
import java.util.Comparator;
@@ -67,7 +68,7 @@ public class JdbcAdapter implements DbAdapter {
6768
private PkGenerator pkGenerator;
6869
protected QuotingStrategy quotingStrategy;
6970

70-
protected Map<Integer, String[]> externalTypes;
71+
protected Map<Integer, NativeColumnType[]> nativeColumnTypes;
7172
protected ExtendedTypeMap extendedTypes;
7273
protected boolean supportsBatchUpdates;
7374
protected boolean supportsUniqueConstraints;
@@ -96,7 +97,7 @@ public JdbcAdapter(@Inject RuntimeProperties runtimeProperties,
9697
this.quotingStrategy = createQuotingStrategy();
9798

9899
this.ejbqlTranslator = createEJBQLTranslator();
99-
this.externalTypes = createExternalTypes();
100+
this.nativeColumnTypes = indexBySqlType(createExternalTypes());
100101
this.extendedTypes = new ExtendedTypeMap();
101102
initExtendedTypes(defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, valueObjectTypeRegistry);
102103
}
@@ -119,50 +120,58 @@ public JdbcEventLogger getJdbcEventLogger() {
119120
}
120121

121122
/**
122-
* Creates the mapping of JDBC types to RDBMS type names used for DDL generation. The first name in each
123-
* array is used for column DDL; some adapters use subsequent names for special cases (e.g. PostgreSQL
124-
* serial types for generated columns). Subclasses override this method, mapping every type supported by
125-
* the target database explicitly, without calling the superclass.
123+
* Returns the database-native types supported by this adapter.
126124
*
127125
* @since 5.0
128126
*/
129-
protected Map<Integer, String[]> createExternalTypes() {
130-
Map<Integer, String[]> types = new HashMap<>();
131-
types.put(Types.ARRAY, new String[]{"ARRAY"});
132-
types.put(Types.BIGINT, new String[]{"BIGINT"});
133-
types.put(Types.ROWID, new String[]{"ROWID"});
134-
types.put(Types.BINARY, new String[]{"BINARY"});
135-
types.put(Types.BIT, new String[]{"BIT"});
136-
types.put(Types.BLOB, new String[]{"BLOB"});
137-
types.put(Types.BOOLEAN, new String[]{"BOOLEAN"});
138-
types.put(Types.CHAR, new String[]{"CHAR"});
139-
types.put(Types.NCHAR, new String[]{"NCHAR"});
140-
types.put(Types.CLOB, new String[]{"CLOB"});
141-
types.put(Types.NCLOB, new String[]{"NCLOB"});
142-
types.put(Types.DATALINK, new String[]{"DATALINK"});
143-
types.put(Types.DATE, new String[]{"DATE"});
144-
types.put(Types.DECIMAL, new String[]{"DECIMAL"});
145-
types.put(Types.DOUBLE, new String[]{"DOUBLE"});
146-
types.put(Types.FLOAT, new String[]{"FLOAT"});
147-
types.put(Types.INTEGER, new String[]{"INTEGER"});
148-
types.put(Types.JAVA_OBJECT, new String[]{"JAVA_OBJECT"});
149-
types.put(Types.LONGVARBINARY, new String[]{"LONGVARBINARY"});
150-
types.put(Types.LONGVARCHAR, new String[]{"LONGVARCHAR"});
151-
types.put(Types.LONGNVARCHAR, new String[]{"LONGNVARCHAR"});
152-
types.put(Types.NUMERIC, new String[]{"NUMERIC"});
153-
types.put(Types.OTHER, new String[]{"OTHER"});
154-
types.put(Types.REAL, new String[]{"REAL"});
155-
types.put(Types.REF, new String[]{"REF"});
156-
types.put(Types.SMALLINT, new String[]{"SMALLINT"});
157-
types.put(Types.STRUCT, new String[]{"STRUCT"});
158-
types.put(Types.TIME, new String[]{"TIME"});
159-
types.put(Types.TIMESTAMP, new String[]{"TIMESTAMP"});
160-
types.put(Types.TINYINT, new String[]{"TINYINT"});
161-
types.put(Types.VARBINARY, new String[]{"VARBINARY"});
162-
types.put(Types.VARCHAR, new String[]{"VARCHAR"});
163-
types.put(Types.NVARCHAR, new String[]{"NVARCHAR"});
164-
types.put(Types.SQLXML, new String[]{"SQLXML"});
165-
return types;
127+
protected NativeColumnType[] createExternalTypes() {
128+
return new NativeColumnType[]{
129+
NativeColumnType.of(Types.ARRAY, "ARRAY"),
130+
NativeColumnType.of(Types.BIGINT, "BIGINT"),
131+
NativeColumnType.of(Types.ROWID, "ROWID"),
132+
NativeColumnType.of(Types.BINARY, "BINARY"),
133+
NativeColumnType.of(Types.BIT, "BIT"),
134+
NativeColumnType.of(Types.BLOB, "BLOB"),
135+
NativeColumnType.of(Types.BOOLEAN, "BOOLEAN"),
136+
NativeColumnType.of(Types.CHAR, "CHAR"),
137+
NativeColumnType.of(Types.NCHAR, "NCHAR"),
138+
NativeColumnType.of(Types.CLOB, "CLOB"),
139+
NativeColumnType.of(Types.NCLOB, "NCLOB"),
140+
NativeColumnType.of(Types.DATALINK, "DATALINK"),
141+
NativeColumnType.of(Types.DATE, "DATE"),
142+
NativeColumnType.of(Types.DECIMAL, "DECIMAL"),
143+
NativeColumnType.of(Types.DOUBLE, "DOUBLE"),
144+
NativeColumnType.of(Types.FLOAT, "FLOAT"),
145+
NativeColumnType.of(Types.INTEGER, "INTEGER"),
146+
NativeColumnType.of(Types.JAVA_OBJECT, "JAVA_OBJECT"),
147+
NativeColumnType.of(Types.LONGVARBINARY, "LONGVARBINARY"),
148+
NativeColumnType.of(Types.LONGVARCHAR, "LONGVARCHAR"),
149+
NativeColumnType.of(Types.LONGNVARCHAR, "LONGNVARCHAR"),
150+
NativeColumnType.of(Types.NUMERIC, "NUMERIC"),
151+
NativeColumnType.of(Types.OTHER, "OTHER"),
152+
NativeColumnType.of(Types.REAL, "REAL"),
153+
NativeColumnType.of(Types.REF, "REF"),
154+
NativeColumnType.of(Types.SMALLINT, "SMALLINT"),
155+
NativeColumnType.of(Types.STRUCT, "STRUCT"),
156+
NativeColumnType.of(Types.TIME, "TIME"),
157+
NativeColumnType.of(Types.TIMESTAMP, "TIMESTAMP"),
158+
NativeColumnType.of(Types.TINYINT, "TINYINT"),
159+
NativeColumnType.of(Types.VARBINARY, "VARBINARY"),
160+
NativeColumnType.of(Types.VARCHAR, "VARCHAR"),
161+
NativeColumnType.of(Types.NVARCHAR, "NVARCHAR"),
162+
NativeColumnType.of(Types.SQLXML, "SQLXML"),
163+
};
164+
}
165+
166+
private static Map<Integer, NativeColumnType[]> indexBySqlType(NativeColumnType[] types) {
167+
Map<Integer, List<NativeColumnType>> grouped = new HashMap<>();
168+
for (NativeColumnType type : types) {
169+
grouped.computeIfAbsent(type.jdbcType(), key -> new ArrayList<>()).add(type);
170+
}
171+
172+
Map<Integer, NativeColumnType[]> indexed = new HashMap<>();
173+
grouped.forEach((sqlType, variants) -> indexed.put(sqlType, variants.toArray(new NativeColumnType[0])));
174+
return indexed;
166175
}
167176

168177
/**
@@ -398,15 +407,15 @@ public static String getType(DbAdapter adapter, DbAttribute column) {
398407
return "OTHER";
399408
}
400409

401-
String[] types = adapter.externalTypesForJdbcType(columnType);
410+
NativeColumnType[] types = adapter.nativeColumnTypes(columnType);
402411
if (types == null || types.length == 0) {
403412
String entityName = column.getEntity() != null
404413
? column.getEntity().getFullyQualifiedName()
405414
: "<null>";
406415
throw new CayenneRuntimeException("Undefined type for attribute '%s.%s': %s."
407416
, entityName, column.getName(), column.getType());
408417
}
409-
return types[0];
418+
return types[0].nativeType();
410419
}
411420

412421
/**
@@ -487,9 +496,29 @@ public String createFkConstraint(DbRelationship rel) {
487496
return buf.toString();
488497
}
489498

499+
/**
500+
* @deprecated use {@link #nativeColumnTypes(int)}
501+
*/
502+
@Deprecated(since = "5.0", forRemoval = true)
490503
@Override
491504
public String[] externalTypesForJdbcType(int type) {
492-
return externalTypes.get(type);
505+
NativeColumnType[] variants = nativeColumnTypes.get(type);
506+
if (variants == null) {
507+
return null;
508+
}
509+
String[] names = new String[variants.length];
510+
for (int i = 0; i < variants.length; i++) {
511+
names[i] = variants[i].nativeType();
512+
}
513+
return names;
514+
}
515+
516+
/**
517+
* @since 5.0
518+
*/
519+
@Override
520+
public NativeColumnType[] nativeColumnTypes(int type) {
521+
return nativeColumnTypes.get(type);
493522
}
494523

495524
@Override
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
****************************************************************/
19+
package org.apache.cayenne.dba;
20+
21+
/**
22+
* Describes a single database-native (external) SQL type that a JDBC type (see {@link java.sql.Types}) maps to.
23+
* A JDBC type may map to more than one external type, e.g. a primary name plus the auto-increment variant used
24+
* for generated columns (PostgreSQL "serial").
25+
*
26+
* @since 5.0
27+
*/
28+
public record NativeColumnType(int jdbcType, String nativeType, boolean autoIncrement) {
29+
30+
/**
31+
* Creates a plain external type.
32+
*/
33+
public static NativeColumnType of(int jdbcType, String dbType) {
34+
return new NativeColumnType(jdbcType, dbType, false);
35+
}
36+
37+
/**
38+
* Returns a copy of this type flagged as the auto-increment variant, e.g. PostgreSQL "serial" for
39+
* {@link java.sql.Types#INTEGER}. Used to render generated columns.
40+
*/
41+
public NativeColumnType asAutoIncrement() {
42+
return new NativeColumnType(jdbcType, nativeType, true);
43+
}
44+
}

cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2Adapter.java

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.apache.cayenne.dba.db2;
2121

22+
import org.apache.cayenne.dba.NativeColumnType;
2223
import org.apache.cayenne.access.DataNode;
2324
import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
2425
import org.apache.cayenne.access.translator.ParameterBinding;
@@ -42,9 +43,7 @@
4243

4344
import java.sql.PreparedStatement;
4445
import java.sql.Types;
45-
import java.util.HashMap;
4646
import java.util.List;
47-
import java.util.Map;
4847

4948
/**
5049
* DbAdapter implementation for the DB2 RDBMS.
@@ -65,41 +64,41 @@ public DB2Adapter(@Inject RuntimeProperties runtimeProperties,
6564
}
6665

6766
@Override
68-
protected Map<Integer, String[]> createExternalTypes() {
69-
Map<Integer, String[]> types = new HashMap<>();
70-
types.put(Types.ARRAY, new String[]{"ARRAY"});
71-
types.put(Types.BIGINT, new String[]{"BIGINT"});
72-
types.put(Types.BINARY, new String[]{"CHAR FOR BIT DATA"});
73-
types.put(Types.BIT, new String[]{"SMALLINT"});
74-
types.put(Types.BLOB, new String[]{"BLOB"});
75-
types.put(Types.BOOLEAN, new String[]{"SMALLINT"});
76-
types.put(Types.CHAR, new String[]{"CHAR"});
77-
types.put(Types.CLOB, new String[]{"CLOB"});
78-
types.put(Types.DATALINK, new String[]{"DATALINK"});
79-
types.put(Types.DATE, new String[]{"DATE"});
80-
types.put(Types.DECIMAL, new String[]{"DECIMAL"});
81-
types.put(Types.DOUBLE, new String[]{"DOUBLE"});
82-
types.put(Types.FLOAT, new String[]{"FLOAT"});
83-
types.put(Types.INTEGER, new String[]{"INTEGER"});
84-
types.put(Types.JAVA_OBJECT, new String[]{"JAVA_OBJECT"});
85-
types.put(Types.LONGNVARCHAR, new String[]{"DBCLOB"});
86-
types.put(Types.LONGVARBINARY, new String[]{"BLOB"});
87-
types.put(Types.LONGVARCHAR, new String[]{"CLOB"});
88-
types.put(Types.NCHAR, new String[]{"GRAPHIC"});
89-
types.put(Types.NCLOB, new String[]{"NCLOB"});
90-
types.put(Types.NUMERIC, new String[]{"DECIMAL"});
91-
types.put(Types.NVARCHAR, new String[]{"VARGRAPHIC"});
92-
types.put(Types.OTHER, new String[]{"OTHER"});
93-
types.put(Types.REAL, new String[]{"REAL"});
94-
types.put(Types.REF, new String[]{"REF"});
95-
types.put(Types.SMALLINT, new String[]{"SMALLINT"});
96-
types.put(Types.STRUCT, new String[]{"STRUCT"});
97-
types.put(Types.TIME, new String[]{"TIME"});
98-
types.put(Types.TIMESTAMP, new String[]{"TIMESTAMP"});
99-
types.put(Types.TINYINT, new String[]{"SMALLINT"});
100-
types.put(Types.VARBINARY, new String[]{"VARCHAR FOR BIT DATA"});
101-
types.put(Types.VARCHAR, new String[]{"VARCHAR"});
102-
return types;
67+
protected NativeColumnType[] createExternalTypes() {
68+
return new NativeColumnType[]{
69+
NativeColumnType.of(Types.ARRAY, "ARRAY"),
70+
NativeColumnType.of(Types.BIGINT, "BIGINT"),
71+
NativeColumnType.of(Types.BINARY, "CHAR FOR BIT DATA"),
72+
NativeColumnType.of(Types.BIT, "SMALLINT"),
73+
NativeColumnType.of(Types.BLOB, "BLOB"),
74+
NativeColumnType.of(Types.BOOLEAN, "SMALLINT"),
75+
NativeColumnType.of(Types.CHAR, "CHAR"),
76+
NativeColumnType.of(Types.CLOB, "CLOB"),
77+
NativeColumnType.of(Types.DATALINK, "DATALINK"),
78+
NativeColumnType.of(Types.DATE, "DATE"),
79+
NativeColumnType.of(Types.DECIMAL, "DECIMAL"),
80+
NativeColumnType.of(Types.DOUBLE, "DOUBLE"),
81+
NativeColumnType.of(Types.FLOAT, "FLOAT"),
82+
NativeColumnType.of(Types.INTEGER, "INTEGER"),
83+
NativeColumnType.of(Types.JAVA_OBJECT, "JAVA_OBJECT"),
84+
NativeColumnType.of(Types.LONGNVARCHAR, "DBCLOB"),
85+
NativeColumnType.of(Types.LONGVARBINARY, "BLOB"),
86+
NativeColumnType.of(Types.LONGVARCHAR, "CLOB"),
87+
NativeColumnType.of(Types.NCHAR, "GRAPHIC"),
88+
NativeColumnType.of(Types.NCLOB, "NCLOB"),
89+
NativeColumnType.of(Types.NUMERIC, "DECIMAL"),
90+
NativeColumnType.of(Types.NVARCHAR, "VARGRAPHIC"),
91+
NativeColumnType.of(Types.OTHER, "OTHER"),
92+
NativeColumnType.of(Types.REAL, "REAL"),
93+
NativeColumnType.of(Types.REF, "REF"),
94+
NativeColumnType.of(Types.SMALLINT, "SMALLINT"),
95+
NativeColumnType.of(Types.STRUCT, "STRUCT"),
96+
NativeColumnType.of(Types.TIME, "TIME"),
97+
NativeColumnType.of(Types.TIMESTAMP, "TIMESTAMP"),
98+
NativeColumnType.of(Types.TINYINT, "SMALLINT"),
99+
NativeColumnType.of(Types.VARBINARY, "VARCHAR FOR BIT DATA"),
100+
NativeColumnType.of(Types.VARCHAR, "VARCHAR"),
101+
};
103102
}
104103

105104
@Override

0 commit comments

Comments
 (0)