Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6391e82

Browse files
authoredJan 22, 2025··
Merge pull request #68 from timeplus-io/timeplus-support
Timeplus Support
2 parents cca1ebf + 4cb9411 commit 6391e82

File tree

13 files changed

+854
-0
lines changed

13 files changed

+854
-0
lines changed
 

‎.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,5 @@ buildNumber.properties
137137
*_LOCAL_*.txt
138138
*_REMOTE_*.txt
139139

140+
.DS_Store
141+
*.cfg

‎flyway-database-timeplus/pom.xml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright (C) Red Gate Software Ltd 2010-2024
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
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+
<project xmlns="http://maven.apache.org/POM/4.0.0"
20+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
21+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
22+
<modelVersion>4.0.0</modelVersion>
23+
<parent>
24+
<groupId>org.flywaydb</groupId>
25+
<artifactId>flyway-community-db-support</artifactId>
26+
<version>10.16.3</version>
27+
</parent>
28+
29+
<artifactId>flyway-database-timeplus</artifactId>
30+
<name>${project.artifactId}</name>
31+
32+
<dependencies>
33+
<dependency>
34+
<groupId>${project.groupId}</groupId>
35+
<artifactId>flyway-core</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.projectlombok</groupId>
39+
<artifactId>lombok</artifactId>
40+
<scope>provided</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>com.timeplus</groupId>
44+
<artifactId>timeplus-native-jdbc</artifactId>
45+
<version>2.0.7</version>
46+
<optional>true</optional>
47+
</dependency>
48+
</dependencies>
49+
50+
<build>
51+
<resources>
52+
<resource>
53+
<directory>src/main/resources</directory>
54+
<filtering>true</filtering>
55+
</resource>
56+
</resources>
57+
<plugins>
58+
<plugin>
59+
<artifactId>maven-resources-plugin</artifactId>
60+
</plugin>
61+
<plugin>
62+
<artifactId>maven-jar-plugin</artifactId>
63+
</plugin>
64+
</plugins>
65+
</build>
66+
</project>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database;
36+
37+
import org.flywaydb.core.api.FlywayException;
38+
import org.flywaydb.core.extensibility.PluginMetadata;
39+
import org.flywaydb.core.internal.util.FileUtils;
40+
41+
import java.io.IOException;
42+
import java.nio.charset.StandardCharsets;
43+
44+
public class TimeplusDatabaseExtension implements PluginMetadata {
45+
public String getDescription() {
46+
return "Community-contributed Timeplus database support extension " + readVersion();
47+
}
48+
49+
public static String readVersion() {
50+
try {
51+
return FileUtils.copyToString(
52+
TimeplusDatabaseExtension.class.getClassLoader().getResourceAsStream("org/flywaydb/community/database/timeplus/version.txt"),
53+
StandardCharsets.UTF_8);
54+
} catch (IOException e) {
55+
throw new FlywayException("Unable to read extension version: " + e.getMessage(), e);
56+
}
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database.timeplus;
36+
37+
import lombok.Getter;
38+
import org.flywaydb.core.extensibility.ConfigurationExtension;
39+
40+
import java.util.Map;
41+
42+
@Getter
43+
public class TimeplusConfigurationExtension implements ConfigurationExtension {
44+
private static final String CLUSTER_NAME = "flyway.timeplus.clusterName";
45+
private static final String ZOOKEEPER_PATH = "flyway.timeplus.zookeeperPath";
46+
47+
private static final String ZOOKEEPER_PATH_DEFAULT_VALUE = "/timeplus/tables/{shard}/{database}/{table}";
48+
49+
private String clusterName;
50+
private String zookeeperPath = ZOOKEEPER_PATH_DEFAULT_VALUE;
51+
52+
@Override
53+
public String getNamespace() {
54+
return "timeplus";
55+
}
56+
57+
@Override
58+
public void extractParametersFromConfiguration(Map<String, String> configuration) {
59+
String clusterName = configuration.remove(CLUSTER_NAME);
60+
if (clusterName != null) {
61+
this.clusterName = clusterName;
62+
}
63+
64+
String zookeeperPath = configuration.remove(ZOOKEEPER_PATH);
65+
if (zookeeperPath != null) {
66+
this.zookeeperPath = zookeeperPath;
67+
}
68+
}
69+
70+
@Override
71+
public String getConfigurationParameterFromEnvironmentVariable(String environmentVariable) {
72+
if ("FLYWAY_TIMEPLUS_CLUSTER_NAME".equals(environmentVariable)) {
73+
return CLUSTER_NAME;
74+
}
75+
if ("FLYWAY_TIMEPLUS_ZOOKEEPER_PATH".equals(environmentVariable)) {
76+
return ZOOKEEPER_PATH;
77+
}
78+
return null;
79+
}
80+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database.timeplus;
36+
37+
import org.flywaydb.core.internal.database.base.Connection;
38+
39+
import java.sql.SQLException;
40+
import java.util.Optional;
41+
42+
public class TimeplusConnection extends Connection<TimeplusDatabase> {
43+
private static final String DEFAULT_CATALOG_TERM = "database";
44+
45+
TimeplusConnection(TimeplusDatabase database, java.sql.Connection connection) {
46+
super(database, connection);
47+
}
48+
49+
@Override
50+
protected String getCurrentSchemaNameOrSearchPath() throws SQLException {
51+
var jdbcConnection = getJdbcTemplate().getConnection();
52+
var currentSchema = useCatalog(jdbcConnection) ?
53+
jdbcConnection.getCatalog() : jdbcConnection.getSchema();
54+
55+
return Optional.ofNullable(currentSchema).map(database::unQuote).orElse(null);
56+
}
57+
58+
@Override
59+
public void doChangeCurrentSchemaOrSearchPathTo(String schema) throws SQLException {
60+
// databaseTerm is catalog since driver version 0.5.0
61+
// https://github.com/Timeplus/timeplus-java/issues/1273 & https://github.com/dbeaver/dbeaver/issues/19383
62+
// For compatibility with old libraries, ((TimeplusConnection) getJdbcConnection()).useCatalog() should be checked
63+
var jdbcConnection = getJdbcTemplate().getConnection();
64+
65+
if (useCatalog(jdbcConnection)) {
66+
jdbcConnection.setCatalog(schema);
67+
} else {
68+
jdbcConnection.setSchema(schema);
69+
}
70+
}
71+
72+
protected boolean useCatalog(java.sql.Connection jdbcConnection) throws SQLException {
73+
return DEFAULT_CATALOG_TERM.equals(jdbcConnection.getMetaData().getCatalogTerm());
74+
}
75+
76+
@Override
77+
public TimeplusSchema getSchema(String name) {
78+
return new TimeplusSchema(jdbcTemplate, database, name);
79+
}
80+
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database.timeplus;
36+
37+
import org.flywaydb.core.api.configuration.Configuration;
38+
import org.flywaydb.core.internal.database.base.Database;
39+
import org.flywaydb.core.internal.database.base.Table;
40+
import org.flywaydb.core.internal.exception.FlywaySqlException;
41+
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
42+
import org.flywaydb.core.internal.jdbc.StatementInterceptor;
43+
import org.flywaydb.core.internal.util.Pair;
44+
import org.flywaydb.core.internal.util.StringUtils;
45+
46+
import java.sql.Connection;
47+
import java.sql.SQLException;
48+
49+
public class TimeplusDatabase extends Database<TimeplusConnection> {
50+
51+
private TimeplusConnection systemConnection;
52+
53+
@Override
54+
public boolean useSingleConnection() {
55+
return true;
56+
}
57+
58+
public TimeplusDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
59+
super(configuration, jdbcConnectionFactory, statementInterceptor);
60+
}
61+
62+
public String getClusterName() {
63+
return configuration.getPluginRegister().getPlugin(TimeplusConfigurationExtension.class).getClusterName();
64+
}
65+
66+
public String getZookeeperPath() {
67+
return configuration.getPluginRegister().getPlugin(TimeplusConfigurationExtension.class).getZookeeperPath();
68+
}
69+
70+
public TimeplusConnection getSystemConnection() {
71+
// Queries on system.XX fail with "Code: 81. DB::Exception: Database the_database doesn't exist. (UNKNOWN_DATABASE) (version 23.7.1.2470 (official build))"
72+
// in case the current catalog (database) is not yet created.
73+
// For this reason, we switch to an existing DB before execution. The database might not have been created yet, so we cannot reliably switch back the Schema.
74+
// * mainConnection cannot be used, as this would change the location of the schema history table.
75+
// * jdbcTemplate cannot be used, as this would change the location of the new tables.
76+
// We had to introduce a separate connection, reserved to system database access.
77+
if (systemConnection == null) {
78+
Connection connection = jdbcConnectionFactory.openConnection();
79+
try {
80+
systemConnection = doGetConnection(connection);
81+
systemConnection.doChangeCurrentSchemaOrSearchPathTo("system");
82+
} catch (SQLException e) {
83+
throw new FlywaySqlException("Unable to switch connection to read-only", e);
84+
}
85+
}
86+
return systemConnection;
87+
}
88+
89+
@Override
90+
protected TimeplusConnection doGetConnection(Connection connection) {
91+
return new TimeplusConnection(this, connection);
92+
}
93+
94+
@Override
95+
public void ensureSupported(Configuration configuration) {
96+
}
97+
98+
@Override
99+
public boolean supportsDdlTransactions() {
100+
return false;
101+
}
102+
103+
@Override
104+
public boolean supportsMultiStatementTransactions() {
105+
return false;
106+
}
107+
108+
@Override
109+
public String getBooleanTrue() {
110+
return "1";
111+
}
112+
113+
@Override
114+
public String getBooleanFalse() {
115+
return "0";
116+
}
117+
118+
@Override
119+
public boolean catalogIsSchema() {
120+
return true;
121+
}
122+
123+
@Override
124+
public void close() {
125+
if (systemConnection != null) {
126+
systemConnection.close();
127+
}
128+
129+
super.close();
130+
}
131+
132+
@Override
133+
public String getRawCreateScript(Table table, boolean baseline) {
134+
String clusterName = getClusterName();
135+
boolean isClustered = StringUtils.hasText(clusterName);
136+
137+
String script = "CREATE STREAM IF NOT EXISTS " + table + (isClustered ? (" ON CLUSTER " + clusterName) : "") + "(" +
138+
" installed_rank int32," +
139+
" version nullable(string)," +
140+
" description string," +
141+
" type string," +
142+
" script string," +
143+
" checksum nullable(int32)," +
144+
" installed_by string," +
145+
" installed_on datetime DEFAULT now()," +
146+
" execution_time int32," +
147+
" success bool" +
148+
")";
149+
150+
String engine;
151+
152+
if (isClustered) {
153+
engine = "ReplicatedMergeTree('" + getZookeeperPath() + "', '{replica}')";
154+
} else {
155+
engine = "MergeTree";
156+
}
157+
158+
script += " ENGINE = " + engine +
159+
" PRIMARY KEY (script);";
160+
161+
return script + (baseline ? getBaselineStatement(table) + ";" : "");
162+
}
163+
164+
@Override
165+
public Pair<String, Object> getDeleteStatement(Table table, boolean version, String filter) {
166+
String deleteStatement = "ALTER STREAM " + table + " DELETE WHERE " + this.quote("success") + " = " + this.getBooleanFalse() + " AND " + (version ? this.quote("version") + " = ?" : this.quote("description") + " = ?");
167+
return Pair.of(deleteStatement, filter);
168+
}
169+
170+
@Override
171+
public String getUpdateStatement(Table table) {
172+
return "ALTER STREAM " + table
173+
+ " UPDATE "
174+
+ quote("description") + "=? , "
175+
+ quote("type") + "=? , "
176+
+ quote("checksum") + "=?"
177+
+ " WHERE " + quote("installed_rank") + "=?";
178+
}
179+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database.timeplus;
36+
37+
import org.flywaydb.community.database.TimeplusDatabaseExtension;
38+
import org.flywaydb.core.api.ResourceProvider;
39+
import org.flywaydb.core.api.configuration.Configuration;
40+
import org.flywaydb.core.internal.database.base.BaseDatabaseType;
41+
import org.flywaydb.core.internal.database.base.CommunityDatabaseType;
42+
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
43+
import org.flywaydb.core.internal.jdbc.StatementInterceptor;
44+
import org.flywaydb.core.internal.parser.Parser;
45+
import org.flywaydb.core.internal.parser.ParsingContext;
46+
47+
import java.sql.Connection;
48+
49+
public class TimeplusDatabaseType extends BaseDatabaseType implements CommunityDatabaseType {
50+
@Override
51+
public String getName() {
52+
return "Timeplus";
53+
}
54+
55+
@Override
56+
public int getNullType() {
57+
return 0;
58+
}
59+
60+
@Override
61+
public boolean handlesJDBCUrl(String url) {
62+
return url.startsWith("jdbc:timeplus:");
63+
}
64+
65+
@Override
66+
public String getDriverClass(String url, ClassLoader classLoader) {
67+
return "com.timeplus.jdbc.TimeplusDriver";
68+
}
69+
70+
@Override
71+
public String getBackupDriverClass(String url, ClassLoader classLoader) {
72+
return "com.timeplus.jdbc.TimeplusDriver";
73+
}
74+
75+
@Override
76+
public boolean handlesDatabaseProductNameAndVersion(String databaseProductName, String databaseProductVersion, Connection connection) {
77+
return databaseProductName.startsWith("Timeplus");
78+
}
79+
80+
@Override
81+
public TimeplusDatabase createDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
82+
return new TimeplusDatabase(configuration, jdbcConnectionFactory, statementInterceptor);
83+
}
84+
85+
@Override
86+
public Parser createParser(Configuration configuration, ResourceProvider resourceProvider, ParsingContext parsingContext) {
87+
return new TimeplusParser(configuration, parsingContext, 3);
88+
}
89+
90+
@Override
91+
public boolean detectUserRequiredByUrl(String url) {
92+
return !url.contains("user=");
93+
}
94+
95+
@Override
96+
public boolean detectPasswordRequiredByUrl(String url) {
97+
return !url.contains("password=");
98+
}
99+
100+
@Override
101+
public String getPluginVersion(Configuration config) {
102+
return TimeplusDatabaseExtension.readVersion();
103+
}
104+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database.timeplus;
36+
37+
import org.flywaydb.core.api.configuration.Configuration;
38+
import org.flywaydb.core.internal.parser.*;
39+
40+
import java.io.IOException;
41+
import java.util.Arrays;
42+
import java.util.List;
43+
44+
public class TimeplusParser extends Parser {
45+
private static final String ALTERNATIVE_QUOTE = "$$";
46+
47+
protected TimeplusParser(Configuration configuration, ParsingContext parsingContext, int peekDepth) {
48+
super(configuration, parsingContext, peekDepth);
49+
}
50+
51+
@Override
52+
protected boolean isAlternativeStringLiteral(String peek) {
53+
if (peek.startsWith(ALTERNATIVE_QUOTE)) {
54+
return true;
55+
}
56+
return super.isAlternativeStringLiteral(peek);
57+
}
58+
59+
@Override
60+
protected Token handleAlternativeStringLiteral(PeekingReader reader, ParserContext context, int pos, int line, int col) throws IOException {
61+
String alternativeQuoteOpen = ALTERNATIVE_QUOTE;
62+
String alternativeQuoteEnd = ALTERNATIVE_QUOTE;
63+
64+
String text;
65+
66+
reader.swallow(alternativeQuoteOpen.length());
67+
text = reader.readUntilExcluding(alternativeQuoteOpen, alternativeQuoteEnd);
68+
reader.swallow(alternativeQuoteEnd.length());
69+
70+
return new Token(TokenType.STRING, pos, line, col, text, text, context.getParensDepth());
71+
}
72+
73+
@Override
74+
protected boolean isSingleLineComment(String peek, ParserContext context, int col) {
75+
return peek.startsWith("--") || peek.startsWith("//");
76+
}
77+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database.timeplus;
36+
37+
import org.flywaydb.core.internal.database.base.Schema;
38+
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
39+
import org.flywaydb.core.internal.util.StringUtils;
40+
41+
import java.sql.SQLException;
42+
import java.util.List;
43+
import java.util.Optional;
44+
45+
public class TimeplusSchema extends Schema<TimeplusDatabase, TimeplusTable> {
46+
47+
private static final String DEFAULT_SCHEMA = "default";
48+
49+
/**
50+
* @param jdbcTemplate The Jdbc Template for communicating with the DB.
51+
* @param database The database-specific support.
52+
* @param name The name of the schema.
53+
*/
54+
public TimeplusSchema(JdbcTemplate jdbcTemplate, TimeplusDatabase database, String name) {
55+
super(jdbcTemplate, database, name);
56+
}
57+
58+
@Override
59+
protected boolean doExists() throws SQLException {
60+
TimeplusConnection systemConnection = database.getSystemConnection();
61+
int i = systemConnection.getJdbcTemplate().queryForInt("SELECT COUNT() FROM system.databases WHERE name = ?", name);
62+
return i > 0;
63+
}
64+
65+
@Override
66+
protected boolean doEmpty() throws SQLException {
67+
TimeplusConnection systemConnection = database.getSystemConnection();
68+
int objectCount = systemConnection.getJdbcTemplate().queryForInt("SELECT COUNT() FROM system.tables WHERE database = ?", name) + getObjectCount("FUNCTION")
69+
+ getObjectCount("FORMAT SCHEMA");
70+
return objectCount == 0;
71+
}
72+
73+
@Override
74+
protected void doCreate() throws SQLException {
75+
TimeplusConnection systemConnection = database.getSystemConnection();
76+
String clusterName = database.getClusterName();
77+
boolean isClustered = StringUtils.hasText(clusterName);
78+
systemConnection.getJdbcTemplate().executeStatement("CREATE DATABASE " + database.quote(name) + (false && isClustered ? (" ON CLUSTER " + clusterName) : ""));
79+
}
80+
81+
@Override
82+
protected void doDrop() throws SQLException {
83+
if (database.getMainConnection().getCurrentSchemaNameOrSearchPath().equals(name)) {
84+
database.getMainConnection().doChangeCurrentSchemaOrSearchPathTo(Optional.ofNullable(database.getConfiguration().getDefaultSchema()).orElse(DEFAULT_SCHEMA));
85+
}
86+
String clusterName = database.getClusterName();
87+
boolean isClustered = StringUtils.hasText(clusterName);
88+
jdbcTemplate.executeStatement("DROP DATABASE " + database.quote(name) + (isClustered ? (" ON CLUSTER " + clusterName) : ""));
89+
}
90+
91+
@Override
92+
protected void doClean() throws SQLException {
93+
// TODO: this will drop streams, views, materialized views, when there are dependencies, DROP could fail.
94+
for (TimeplusTable table : allTables()) {
95+
table.drop();
96+
}
97+
for (String dropStatement : generateDropStatements("FORMAT SCHEMA")) {
98+
jdbcTemplate.execute(dropStatement);
99+
}
100+
101+
for (String dropStatement : generateDropStatements("FUNCTION")) {
102+
jdbcTemplate.execute(dropStatement);
103+
}
104+
}
105+
106+
@Override
107+
protected TimeplusTable[] doAllTables() throws SQLException {
108+
TimeplusConnection systemConnection = database.getSystemConnection();
109+
return systemConnection.getJdbcTemplate().queryForStringList("SELECT name FROM system.tables WHERE database = ?", name)
110+
.stream()
111+
.map(this::getTable)
112+
.toArray(TimeplusTable[]::new);
113+
}
114+
115+
@Override
116+
public TimeplusTable getTable(String tableName) {
117+
return new TimeplusTable(jdbcTemplate, database, this, tableName);
118+
}
119+
120+
private int getObjectCount(String objectType) throws SQLException {
121+
return jdbcTemplate.query("SHOW " + objectType + "S", rs -> 1).size();
122+
}
123+
124+
private List<String> generateDropStatements(final String objectType) throws SQLException {
125+
return jdbcTemplate.query("SHOW " + objectType + "S", rs -> {
126+
String resName = rs.getString("name");
127+
return "DROP " + objectType + " " + database.quote(resName);
128+
});
129+
}
130+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*-
2+
* ========================LICENSE_START=================================
3+
* flyway-database-timeplus
4+
* ========================================================================
5+
* Copyright (C) 2010 - 2024 Red Gate Software Ltd
6+
* ========================================================================
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =========================LICENSE_END==================================
19+
*/
20+
/*
21+
* Copyright (C) Red Gate Software Ltd 2010-2024
22+
*
23+
* Licensed under the Apache License, Version 2.0 (the "License");
24+
* you may not use this file except in compliance with the License.
25+
* You may obtain a copy of the License at
26+
*
27+
* http://www.apache.org/licenses/LICENSE-2.0
28+
*
29+
* Unless required by applicable law or agreed to in writing, software
30+
* distributed under the License is distributed on an "AS IS" BASIS,
31+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32+
* See the License for the specific language governing permissions and
33+
* limitations under the License.
34+
*/
35+
package org.flywaydb.community.database.timeplus;
36+
37+
import lombok.CustomLog;
38+
import org.flywaydb.core.internal.database.base.Table;
39+
import org.flywaydb.core.internal.jdbc.JdbcTemplate;
40+
import org.flywaydb.core.internal.util.StringUtils;
41+
42+
import java.sql.SQLException;
43+
44+
@CustomLog
45+
public class TimeplusTable extends Table<TimeplusDatabase, TimeplusSchema> {
46+
/**
47+
* @param jdbcTemplate The JDBC template for communicating with the DB.
48+
* @param database The database-specific support.
49+
* @param schema The schema this table lives in.
50+
* @param name The name of the table.
51+
*/
52+
public TimeplusTable(JdbcTemplate jdbcTemplate, TimeplusDatabase database, TimeplusSchema schema, String name) {
53+
super(jdbcTemplate, database, schema, name);
54+
}
55+
56+
@Override
57+
protected void doDrop() throws SQLException {
58+
String clusterName = database.getClusterName();
59+
60+
jdbcTemplate.executeStatement("DROP STREAM " + this + (StringUtils.hasText(clusterName) ? (" ON CLUSTER " + clusterName) : ""));
61+
}
62+
63+
@Override
64+
protected boolean doExists() throws SQLException {
65+
TimeplusConnection systemConnection = database.getSystemConnection();
66+
int count = systemConnection.getJdbcTemplate().queryForInt("SELECT COUNT() FROM system.tables WHERE database = ? AND name = ?", schema.getName(), name);
67+
return count > 0;
68+
}
69+
70+
@Override
71+
protected void doLock() throws SQLException {
72+
LOG.debug("Unable to lock " + this + " as Timeplus does not support locking. No concurrent migration supported.");
73+
}
74+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.flywaydb.community.database.timeplus.TimeplusConfigurationExtension
2+
org.flywaydb.community.database.timeplus.TimeplusDatabaseType
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
${pom.version}

‎pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<module>flyway-database-databricks</module>
4141
<module>flyway-database-db2zos</module>
4242
<module>flyway-community-db-support-archetype</module>
43+
<module>flyway-database-timeplus</module>
4344
</modules>
4445

4546
<properties>

0 commit comments

Comments
 (0)
Please sign in to comment.