Skip to content

Commit fe0180f

Browse files
authored
[Feature][Connector-V2] Jdbc connector support SAP HANA. (#3017)
1 parent b9164b8 commit fe0180f

File tree

11 files changed

+392
-3
lines changed

11 files changed

+392
-3
lines changed

docs/en/connector-v2/sink/Jdbc.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ there are some reference value for params above.
149149
| GBase8a | com.gbase.jdbc.Driver | jdbc:gbase://e2e_gbase8aDb:5258/test | / | https://www.gbase8.cn/wp-content/uploads/2020/10/gbase-connector-java-8.3.81.53-build55.5.7-bin_min_mix.jar |
150150
| StarRocks | com.mysql.cj.jdbc.Driver | jdbc:mysql://localhost:3306/test | / | https://mvnrepository.com/artifact/mysql/mysql-connector-java |
151151
| db2 | com.ibm.db2.jcc.DB2Driver | jdbc:db2://localhost:50000/testdb | com.ibm.db2.jcc.DB2XADataSource | https://mvnrepository.com/artifact/com.ibm.db2.jcc/db2jcc/db2jcc4 |
152+
| saphana | com.sap.db.jdbc.Driver | jdbc:sap://localhost:39015 | / | https://mvnrepository.com/artifact/com.sap.cloud.db.jdbc/ngdbc |
152153
| Doris | com.mysql.cj.jdbc.Driver | jdbc:mysql://localhost:3306/test | / | https://mvnrepository.com/artifact/mysql/mysql-connector-java |
153154
| teradata | com.teradata.jdbc.TeraDriver | jdbc:teradata://localhost/DBS_PORT=1025,DATABASE=test | / | https://mvnrepository.com/artifact/com.teradata.jdbc/terajdbc |
154155
| Redshift | com.amazon.redshift.jdbc42.Driver | jdbc:redshift://localhost:5439/testdb | com.amazon.redshift.xa.RedshiftXADataSource | https://mvnrepository.com/artifact/com.amazon.redshift/redshift-jdbc42 |

docs/en/connector-v2/source/Jdbc.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ there are some reference value for params above.
115115
| starrocks | com.mysql.cj.jdbc.Driver | jdbc:mysql://localhost:3306/test | https://mvnrepository.com/artifact/mysql/mysql-connector-java |
116116
| db2 | com.ibm.db2.jcc.DB2Driver | jdbc:db2://localhost:50000/testdb | https://mvnrepository.com/artifact/com.ibm.db2.jcc/db2jcc/db2jcc4 |
117117
| tablestore | com.alicloud.openservices.tablestore.jdbc.OTSDriver | "jdbc:ots:http s://myinstance.cn-hangzhou.ots.aliyuncs.com/myinstance" | https://mvnrepository.com/artifact/com.aliyun.openservices/tablestore-jdbc |
118+
| saphana | com.sap.db.jdbc.Driver | jdbc:sap://localhost:39015 | https://mvnrepository.com/artifact/com.sap.cloud.db.jdbc/ngdbc |
118119
| doris | com.mysql.cj.jdbc.Driver | jdbc:mysql://localhost:3306/test | https://mvnrepository.com/artifact/mysql/mysql-connector-java |
119120
| teradata | com.teradata.jdbc.TeraDriver | jdbc:teradata://localhost/DBS_PORT=1025,DATABASE=test | https://mvnrepository.com/artifact/com.teradata.jdbc/terajdbc |
120121
| Redshift | com.amazon.redshift.jdbc42.Driver | jdbc:redshift://localhost:5439/testdb | https://mvnrepository.com/artifact/com.amazon.redshift/redshift-jdbc42 |

seatunnel-connectors-v2/connector-jdbc/pom.xml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<tablestore.version>5.13.9</tablestore.version>
4343
<teradata.version>17.20.00.12</teradata.version>
4444
<redshift.version>2.1.0.9</redshift.version>
45+
<saphana.version>2.14.7</saphana.version>
4546
</properties>
4647

4748
<dependencyManagement>
@@ -114,6 +115,13 @@
114115
<version>${redshift.version}</version>
115116
<scope>provided</scope>
116117
</dependency>
118+
<!-- https://mvnrepository.com/artifact/com.sap.cloud.db.jdbc/ngdbc -->
119+
<dependency>
120+
<groupId>com.sap.cloud.db.jdbc</groupId>
121+
<artifactId>ngdbc</artifactId>
122+
<version>${saphana.version}</version>
123+
<scope>provided</scope>
124+
</dependency>
117125
</dependencies>
118126
</dependencyManagement>
119127

@@ -171,6 +179,10 @@
171179
<groupId>com.amazon.redshift</groupId>
172180
<artifactId>redshift-jdbc42</artifactId>
173181
</dependency>
174-
</dependencies>
175182

176-
</project>
183+
<dependency>
184+
<groupId>com.sap.cloud.db.jdbc</groupId>
185+
<artifactId>ngdbc</artifactId>
186+
</dependency>
187+
</dependencies>
188+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.saphana;
20+
21+
import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.converter.JdbcRowConverter;
22+
import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialect;
23+
import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialectTypeMapper;
24+
25+
import java.util.Optional;
26+
27+
public class SapHanaDialect implements JdbcDialect {
28+
@Override
29+
public String dialectName() {
30+
return "SapHana";
31+
}
32+
33+
@Override
34+
public JdbcRowConverter getRowConverter() {
35+
return new SapHanaJdbcRowConverter();
36+
}
37+
38+
@Override
39+
public JdbcDialectTypeMapper getJdbcDialectTypeMapper() {
40+
return new SapHanaTypeMapper();
41+
}
42+
43+
@Override
44+
public Optional<String> getUpsertStatement(String tableName, String[] fieldNames, String[] uniqueKeyFields) {
45+
return Optional.empty();
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.saphana;
20+
21+
import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialect;
22+
import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialectFactory;
23+
24+
import com.google.auto.service.AutoService;
25+
26+
/**
27+
* Dialect Factory of {@link SapHanaDialect}
28+
*/
29+
30+
@AutoService(JdbcDialectFactory.class)
31+
public class SapHanaDialectFactory implements JdbcDialectFactory {
32+
@Override
33+
public boolean acceptsURL(String url) {
34+
return url.startsWith("jdbc:sap://");
35+
}
36+
37+
@Override
38+
public JdbcDialect create() {
39+
return new SapHanaDialect();
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.saphana;
20+
21+
import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.converter.AbstractJdbcRowConverter;
22+
23+
public class SapHanaJdbcRowConverter extends AbstractJdbcRowConverter {
24+
@Override
25+
public String converterName() {
26+
return "SapHana";
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.saphana;
20+
21+
import org.apache.seatunnel.api.table.type.BasicType;
22+
import org.apache.seatunnel.api.table.type.DecimalType;
23+
import org.apache.seatunnel.api.table.type.LocalTimeType;
24+
import org.apache.seatunnel.api.table.type.PrimitiveByteArrayType;
25+
import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
26+
import org.apache.seatunnel.connectors.seatunnel.jdbc.internal.dialect.JdbcDialectTypeMapper;
27+
28+
import java.sql.ResultSetMetaData;
29+
import java.sql.SQLException;
30+
import java.util.Locale;
31+
32+
public class SapHanaTypeMapper implements JdbcDialectTypeMapper {
33+
34+
// refer to https://help.sap.com/docs/SAP_BUSINESSOBJECTS_BUSINESS_INTELLIGENCE_PLATFORM/aa4cb9ab429349e49678e146f05d7341/ec3313286fdb101497906a7cb0e91070.html?locale=zh-CN
35+
private static final String SAP_HANA_BLOB = "blob";
36+
private static final String SAP_HANA_VARBINARY = "varbinary";
37+
private static final String SAP_HANA_DATE = "date";
38+
private static final String SAP_HANA_TIME = "time";
39+
private static final String SAP_HANA_LONGDATE = "longtime";
40+
private static final String SAP_HANA_SECONDDATE = "seconddate";
41+
private static final String SAP_HANA_TIMESTAMP = "timestamp";
42+
private static final String SAP_HANA_DECIMAL = "decimal";
43+
private static final String SAP_HANA_REAL = "real";
44+
private static final String SAP_HANA_SMALLDECIMAL = "smalldecimal";
45+
private static final String SAP_HANA_BIGINT = "bigint";
46+
private static final String SAP_HANA_INTEGER = "integer";
47+
private static final String SAP_HANA_SMALLINT = "smallint";
48+
private static final String SAP_HANA_TINYINT = "tinyint";
49+
private static final String SAP_HANA_DOUBLE = "double";
50+
private static final String SAP_HANA_CLOB = "clob";
51+
private static final String SAP_HANA_NCLOB = "nclob";
52+
private static final String SAP_HANA_TEXT = "text";
53+
private static final String SAP_HANA_ALPHANUM = "alphanum";
54+
private static final String SAP_HANA_NVARCHAR = "nvarchar";
55+
private static final String SAP_HANA_SHORTTEXT = "shorttext";
56+
private static final String SAP_HANA_VARCHAR = "varchar";
57+
private static final String SAP_HANA_BINARY = "binary";
58+
59+
@Override
60+
public SeaTunnelDataType<?> mapping(ResultSetMetaData metadata, int colIndex) throws SQLException {
61+
String typeName = metadata.getColumnTypeName(colIndex).toLowerCase(Locale.ROOT);
62+
63+
int precision = metadata.getPrecision(colIndex);
64+
int scale = metadata.getScale(colIndex);
65+
66+
switch (typeName) {
67+
case SAP_HANA_BLOB:
68+
case SAP_HANA_VARBINARY:
69+
case SAP_HANA_BINARY:
70+
return PrimitiveByteArrayType.INSTANCE;
71+
case SAP_HANA_DATE:
72+
return LocalTimeType.LOCAL_DATE_TYPE;
73+
case SAP_HANA_TIME:
74+
return LocalTimeType.LOCAL_TIME_TYPE;
75+
case SAP_HANA_TIMESTAMP:
76+
case SAP_HANA_LONGDATE:
77+
case SAP_HANA_SECONDDATE:
78+
return LocalTimeType.LOCAL_DATE_TIME_TYPE;
79+
case SAP_HANA_DECIMAL:
80+
return new DecimalType(precision, scale);
81+
case SAP_HANA_REAL:
82+
case SAP_HANA_SMALLDECIMAL:
83+
return BasicType.FLOAT_TYPE;
84+
case SAP_HANA_BIGINT:
85+
return BasicType.LONG_TYPE;
86+
case SAP_HANA_INTEGER:
87+
return BasicType.INT_TYPE;
88+
case SAP_HANA_SMALLINT:
89+
return BasicType.SHORT_TYPE;
90+
case SAP_HANA_TINYINT:
91+
return BasicType.BYTE_TYPE;
92+
case SAP_HANA_DOUBLE:
93+
return BasicType.DOUBLE_TYPE;
94+
case SAP_HANA_CLOB:
95+
case SAP_HANA_NCLOB:
96+
case SAP_HANA_TEXT:
97+
case SAP_HANA_ALPHANUM:
98+
case SAP_HANA_NVARCHAR:
99+
case SAP_HANA_SHORTTEXT:
100+
case SAP_HANA_VARCHAR:
101+
return BasicType.STRING_TYPE;
102+
default:
103+
final String jdbcColumnName = metadata.getColumnName(colIndex);
104+
throw new UnsupportedOperationException(
105+
String.format(
106+
"Doesn't support SapHana type '%s' on column '%s' yet.",
107+
typeName, jdbcColumnName));
108+
}
109+
}
110+
}

seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@
108108
<artifactId>terajdbc4</artifactId>
109109
<scope>test</scope>
110110
</dependency>
111+
<dependency>
112+
<groupId>com.sap.cloud.db.jdbc</groupId>
113+
<artifactId>ngdbc</artifactId>
114+
<scope>test</scope>
115+
</dependency>
111116
</dependencies>
112117

113118
</project>

seatunnel-e2e/seatunnel-connector-v2-e2e/connector-jdbc-e2e/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/AbstractJdbcIT.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.testcontainers.containers.GenericContainer;
3838
import org.testcontainers.containers.output.Slf4jLogConsumer;
3939
import org.testcontainers.lifecycle.Startables;
40+
import org.testcontainers.utility.DockerLoggerFactory;
4041

4142
import java.io.IOException;
4243
import java.net.MalformedURLException;
@@ -83,7 +84,7 @@ private void getContainer() throws SQLException, MalformedURLException, ClassNot
8384
.withNetwork(NETWORK)
8485
.withNetworkAliases(jdbcCase.getNetworkAliases())
8586
.withEnv(jdbcCase.getContainerEnv())
86-
.withLogConsumer(new Slf4jLogConsumer(log));
87+
.withLogConsumer(new Slf4jLogConsumer(DockerLoggerFactory.getLogger(jdbcCase.getDockerImage())));
8788
dbServer.setPortBindings(Lists.newArrayList(
8889
String.format("%s:%s", jdbcCase.getLocalPort(), jdbcCase.getPort())));
8990
Startables.deepStart(Stream.of(dbServer)).join();

0 commit comments

Comments
 (0)