Skip to content

Commit c09eeee

Browse files
committed
add test
1 parent d520d0d commit c09eeee

File tree

6 files changed

+158
-39
lines changed

6 files changed

+158
-39
lines changed

paimon-core/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,13 @@ under the License.
189189
<version>3.6.1</version>
190190
</dependency>
191191

192+
<dependency>
193+
<groupId>org.xerial</groupId>
194+
<artifactId>sqlite-jdbc</artifactId>
195+
<version>3.44.0.0</version>
196+
<scope>test</scope>
197+
</dependency>
198+
192199
</dependencies>
193200

194201
<build>

paimon-core/src/main/java/org/apache/paimon/jdbc/JdbcCatalog.java

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.apache.paimon.fs.Path;
2626
import org.apache.paimon.operation.Lock;
2727
import org.apache.paimon.options.CatalogOptions;
28-
import org.apache.paimon.options.Options;
2928
import org.apache.paimon.schema.Schema;
3029
import org.apache.paimon.schema.SchemaChange;
3130
import org.apache.paimon.schema.SchemaManager;
@@ -46,6 +45,7 @@
4645
import java.sql.ResultSet;
4746
import java.sql.SQLException;
4847
import java.util.AbstractMap;
48+
import java.util.HashMap;
4949
import java.util.List;
5050
import java.util.Map;
5151
import java.util.Optional;
@@ -70,19 +70,23 @@ public class JdbcCatalog extends AbstractCatalog {
7070
private Map<String, String> configuration;
7171
private final String warehouse;
7272

73-
protected JdbcCatalog(FileIO fileIO, String catalogName, Options options, String warehouse) {
73+
protected JdbcCatalog(
74+
FileIO fileIO, String catalogName, Map<String, String> config, String warehouse) {
7475
super(fileIO);
7576
if (!StringUtils.isBlank(catalogName)) {
7677
this.catalogName = catalogName;
7778
}
78-
this.configuration = options.toMap();
79+
this.configuration = config;
7980
this.warehouse = warehouse;
8081
Preconditions.checkNotNull(configuration, "Invalid catalog properties: null");
8182
this.connections =
8283
new JdbcClientPool(
83-
options.get(CatalogOptions.CLIENT_POOL_SIZE),
84-
options.get(CatalogOptions.URI),
85-
this.configuration);
84+
Integer.parseInt(
85+
config.getOrDefault(
86+
CatalogOptions.CLIENT_POOL_SIZE.key(),
87+
CatalogOptions.CLIENT_POOL_SIZE.defaultValue().toString())),
88+
configuration.get(CatalogOptions.URI.key()),
89+
configuration);
8690
try {
8791
initializeCatalogTablesIfNeed();
8892
} catch (SQLException e) {
@@ -97,7 +101,7 @@ private void initializeCatalogTablesIfNeed() throws SQLException, InterruptedExc
97101
boolean initializeCatalogTables =
98102
Boolean.parseBoolean(
99103
configuration.getOrDefault(INITIALIZE_CATALOG_TABLES.key(), "false"));
100-
String uri = configuration.get(CatalogOptions.URI);
104+
String uri = configuration.get(CatalogOptions.URI.key());
101105
Preconditions.checkNotNull(uri, "JDBC connection URI is required");
102106
if (initializeCatalogTables) {
103107
// Check and create catalog table.
@@ -133,6 +137,24 @@ private void initializeCatalogTablesIfNeed() throws SQLException, InterruptedExc
133137
return conn.prepareStatement(JdbcUtils.CREATE_DATABASE_PROPERTIES_TABLE)
134138
.execute();
135139
});
140+
141+
// Check and create distributed lock table.
142+
connections.run(
143+
conn -> {
144+
DatabaseMetaData dbMeta = conn.getMetaData();
145+
ResultSet tableExists =
146+
dbMeta.getTables(
147+
null /* catalog name */,
148+
null /* schemaPattern */,
149+
JdbcUtils
150+
.DISTRIBUTED_LOCKS_TABLE_NAME /* tableNamePattern */,
151+
null /* types */);
152+
if (tableExists.next()) {
153+
return true;
154+
}
155+
return conn.prepareStatement(JdbcUtils.CREATE_DISTRIBUTED_LOCK_TABLE_SQL)
156+
.execute();
157+
});
136158
}
137159
}
138160

@@ -149,6 +171,12 @@ public List<String> listDatabases() {
149171
row -> row.getString(JdbcUtils.TABLE_DATABASE),
150172
JdbcUtils.LIST_ALL_TABLE_DATABASES_SQL,
151173
catalogName));
174+
175+
namespaces.addAll(
176+
fetch(
177+
row -> row.getString(JdbcUtils.DATABASE_NAME),
178+
JdbcUtils.LIST_ALL_PROPERTY_DATABASES_SQL,
179+
catalogName));
152180
return namespaces;
153181
}
154182

@@ -177,15 +205,10 @@ protected void createDatabaseImpl(String name, Map<String, String> properties) {
177205
throw new RuntimeException(String.format("Database already exists: %s", name));
178206
}
179207

180-
Map<String, String> createProps;
181-
if (properties == null || properties.isEmpty()) {
182-
createProps = ImmutableMap.of(DATABASE_EXISTS_PROPERTY, "true");
183-
} else {
184-
createProps =
185-
ImmutableMap.<String, String>builder()
186-
.putAll(properties)
187-
.put(DATABASE_EXISTS_PROPERTY, "true")
188-
.build();
208+
Map<String, String> createProps = new HashMap<>();
209+
createProps.put(DATABASE_EXISTS_PROPERTY, "true");
210+
if (properties != null && !properties.isEmpty()) {
211+
createProps.putAll(properties);
189212
}
190213

191214
if (!createProps.containsKey(DB_LOCATION_PROP)) {
@@ -197,21 +220,9 @@ protected void createDatabaseImpl(String name, Map<String, String> properties) {
197220

198221
@Override
199222
protected void dropDatabaseImpl(String name) {
200-
if (!databaseExists(name)) {
201-
return;
202-
}
203-
try {
204-
List<String> tablesInDatabase = listTables(name);
205-
// Database cannot be deleted when a table exists
206-
if (tablesInDatabase != null && !tablesInDatabase.isEmpty()) {
207-
throw new RuntimeException(
208-
String.format(
209-
"Database %s is not empty. %s tables exist.",
210-
name, tablesInDatabase.size()));
211-
}
212-
} catch (DatabaseNotExistException e) {
213-
throw new RuntimeException(e);
214-
}
223+
// delete table
224+
execute(connections, JdbcUtils.DELETE_TABLES_SQL, catalogName, name);
225+
// delete properties
215226
execute(connections, JdbcUtils.DELETE_ALL_DATABASE_PROPERTIES_SQL, catalogName, name);
216227
}
217228

@@ -315,11 +326,7 @@ protected void renameTableImpl(Identifier fromTable, Identifier toTable) {
315326
}
316327
// Update table metadata
317328
updateTableMetadataLocation(
318-
connections,
319-
catalogName,
320-
fromTable,
321-
toPath.toString(),
322-
fromPath.toString());
329+
connections, catalogName, toTable, toPath.toString(), fromPath.toString());
323330
}
324331
} catch (Exception e) {
325332
throw new RuntimeException("Failed to rename table " + fromTable.getFullName(), e);
@@ -380,6 +387,11 @@ public boolean tableExists(Identifier identifier) {
380387
connections, catalogName, identifier.getDatabaseName(), identifier.getObjectName());
381388
}
382389

390+
@Override
391+
public boolean caseSensitive() {
392+
return false;
393+
}
394+
383395
@Override
384396
public Optional<CatalogLock.Factory> lockFactory() {
385397
return lockEnabled()

paimon-core/src/main/java/org/apache/paimon/jdbc/JdbcCatalogFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ public String identifier() {
3636

3737
@Override
3838
public Catalog create(FileIO fileIO, Path warehouse, CatalogContext context) {
39-
return new JdbcCatalog(fileIO, null, context.options(), warehouse.getName());
39+
return new JdbcCatalog(fileIO, null, context.options().toMap(), warehouse.getName());
4040
}
4141
}

paimon-core/src/main/java/org/apache/paimon/jdbc/JdbcUtils.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ public class JdbcUtils {
104104
+ " = ? AND "
105105
+ TABLE_DATABASE
106106
+ " = ?";
107+
108+
static final String DELETE_TABLES_SQL =
109+
"DELETE FROM "
110+
+ CATALOG_TABLE_NAME
111+
+ " WHERE "
112+
+ CATALOG_NAME
113+
+ " = ? AND "
114+
+ TABLE_DATABASE
115+
+ " = ?";
107116
static final String RENAME_TABLE_SQL =
108117
"UPDATE "
109118
+ CATALOG_TABLE_NAME
@@ -273,7 +282,7 @@ public class JdbcUtils {
273282
static final String LOCK_NAME = "lock_name";
274283
static final String ACQUIRED_AT = "acquired_at";
275284

276-
static final String CREATE_DISTRIBUTED_LOCK_TABLE =
285+
static final String CREATE_DISTRIBUTED_LOCK_TABLE_SQL =
277286
"CREATE TABLE "
278287
+ DISTRIBUTED_LOCKS_TABLE_NAME
279288
+ "("
@@ -501,7 +510,7 @@ public static int execute(
501510
return connections.run(
502511
conn -> {
503512
try (PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
504-
for (int pos = 0; pos < args.length; pos += 1) {
513+
for (int pos = 0; pos < args.length; pos++) {
505514
preparedStatement.setString(pos + 1, args[pos]);
506515
}
507516
return preparedStatement.executeUpdate();

paimon-core/src/main/resources/META-INF/services/org.apache.paimon.factories.Factory

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
# limitations under the License.
1515

1616
org.apache.paimon.catalog.FileSystemCatalogFactory
17+
org.apache.paimon.jdbc.JdbcCatalogFactory
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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.paimon.jdbc;
20+
21+
import org.apache.paimon.catalog.CatalogTestBase;
22+
import org.apache.paimon.catalog.Identifier;
23+
import org.apache.paimon.options.CatalogOptions;
24+
25+
import org.apache.paimon.shade.guava30.com.google.common.collect.Maps;
26+
27+
import org.junit.jupiter.api.BeforeEach;
28+
import org.junit.jupiter.api.Test;
29+
30+
import java.util.ArrayList;
31+
import java.util.List;
32+
import java.util.Map;
33+
import java.util.UUID;
34+
35+
import static org.assertj.core.api.Assertions.assertThat;
36+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
37+
38+
/** Tests for {@link JdbcCatalog}. */
39+
public class JdbcCatalogTest extends CatalogTestBase {
40+
41+
@BeforeEach
42+
public void setUp() throws Exception {
43+
super.setUp();
44+
catalog = initCatalog("test-jdbc-catalog", Maps.newHashMap());
45+
}
46+
47+
private JdbcCatalog initCatalog(String catalogName, Map<String, String> props) {
48+
Map<String, String> properties = Maps.newHashMap();
49+
properties.put(
50+
CatalogOptions.URI.key(),
51+
"jdbc:sqlite:file::memory:?ic" + UUID.randomUUID().toString().replace("-", ""));
52+
53+
properties.put(JdbcCatalog.PROPERTY_PREFIX + "username", "user");
54+
properties.put(JdbcCatalog.PROPERTY_PREFIX + "password", "password");
55+
properties.put(CatalogOptions.WAREHOUSE.key(), warehouse);
56+
properties.put(JdbcCatalogOptions.INITIALIZE_CATALOG_TABLES.key(), "true");
57+
properties.putAll(props);
58+
JdbcCatalog jdbcCatalog = new JdbcCatalog(fileIO, catalogName, properties, warehouse);
59+
return jdbcCatalog;
60+
}
61+
62+
@Test
63+
@Override
64+
public void testListDatabasesWhenNoDatabases() {
65+
List<String> databases = catalog.listDatabases();
66+
assertThat(databases).isEqualTo(new ArrayList<>());
67+
}
68+
69+
@Test
70+
public void testCheckIdentifierUpperCase() throws Exception {
71+
catalog.createDatabase("test_db", false);
72+
assertThatThrownBy(
73+
() ->
74+
catalog.createTable(
75+
Identifier.create("TEST_DB", "new_table"),
76+
DEFAULT_TABLE_SCHEMA,
77+
false))
78+
.isInstanceOf(IllegalArgumentException.class)
79+
.hasMessage("Database name [TEST_DB] cannot contain upper case in the catalog.");
80+
81+
assertThatThrownBy(
82+
() ->
83+
catalog.createTable(
84+
Identifier.create("test_db", "NEW_TABLE"),
85+
DEFAULT_TABLE_SCHEMA,
86+
false))
87+
.isInstanceOf(IllegalArgumentException.class)
88+
.hasMessage("Table name [NEW_TABLE] cannot contain upper case in the catalog.");
89+
}
90+
}

0 commit comments

Comments
 (0)