Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TiberoDB Suport #58

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c03db5e
init
w-seok Jul 30, 2024
1036172
flyway for tibero structure setting
birdieHyun Jul 30, 2024
fa0f4da
feat: add TiberoConnection
w-seok Aug 1, 2024
435dbfb
create version.txt
YGwan Aug 1, 2024
37985aa
flyway for tibero database extension
YGwan Aug 1, 2024
cef6563
feat: add TiberoDatabaseType
Bellroute Aug 1, 2024
6220fb8
add TiberoTable
seunghan0421 Aug 1, 2024
b77e793
add TiberoDatabase zero to catalog
seunghan0421 Aug 1, 2024
a9f2907
add TiberoDatabase rawScript, xml db, role grant
birdieHyun Aug 1, 2024
8df3b95
add TiberoDatabase queryReturnsRows, isDataDicViewAccessible
Bellroute Aug 1, 2024
7ea55f2
feat: add TiberoDatabase systemSchema, dbOrAll, locatorAvailable
w-seok Aug 1, 2024
a4fa517
add TiberoDatabase isFlashbackDataArchiveAvailable
YGwan Aug 1, 2024
11f9b1d
add tibero schema
birdieHyun Aug 1, 2024
4d6eb45
add tibero schema trigger, queue_table, scheduler_chain, scheduler_jo…
Bellroute Aug 1, 2024
d373665
add tibero schema schedule, sql_translation_profile, materialized_vie…
YGwan Aug 1, 2024
479605a
add tibero schema view, table, index, sequence, function
birdieHyun Aug 1, 2024
138bd4b
add TiberoSchema procedure, package, package_body, library
seunghan0421 Aug 1, 2024
d1031bd
add TiberoSchema type, directory, synonym, database_link, credential,…
w-seok Aug 1, 2024
c3e6687
chore : change default schema
birdieHyun Aug 26, 2024
d450250
flyway for tibero baseline test
birdieHyun Aug 14, 2024
b10dc11
Separate Flyway creation logic
birdieHyun Aug 16, 2024
c120dc5
add test_sql for validate test
YGwan Aug 14, 2024
bb9499e
add validate test
YGwan Aug 14, 2024
69b2592
add info test
Bellroute Aug 14, 2024
e083186
add repair test
w-seok Aug 19, 2024
53af9dc
Adapted to team conventions
birdieHyun Aug 19, 2024
677251a
migration test
seunghan0421 Aug 19, 2024
c393b8a
simple test SoftAssertions로 수정
seunghan0421 Aug 19, 2024
2a56b3f
simple test SoftAssertions로 수정2
seunghan0421 Aug 19, 2024
580a73d
불필요한 개행 삭제
seunghan0421 Aug 19, 2024
0538f5e
clean test 추가
seunghan0421 Aug 27, 2024
85bed4f
Clean test setUp 메서드 수정 및 Scheduler 비활성화
seunghan0421 Aug 30, 2024
d00a192
softAssertions.assertAll() 추가
seunghan0421 Sep 2, 2024
366f068
test 환경 local database에서 testContainer로 변경
w-seok Sep 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions flyway-database-tibero/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-community-db-support</artifactId>
<version>10.16.0</version>
</parent>

<artifactId>flyway-database-tibero</artifactId>
<name>${project.artifactId}</name>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>com.tmax.tibero</groupId>
<artifactId>tibero-jdbc</artifactId>
<version>7</version>
<scope>system</scope>
<systemPath>${basedir}/libs/tibero7-jdbc.jar</systemPath>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.18.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.18.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.flywaydb.community.database;

import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.extensibility.PluginMetadata;
import org.flywaydb.core.internal.util.FileUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

public class TiberoDatabaseExtension implements PluginMetadata {

public String getDescription() {
return "Community-contributed Tibero database support extension " + readVersion() + " by Redgate";
}

public static String readVersion() {
try {
return FileUtils.copyToString(
Objects.requireNonNull(TiberoDatabaseExtension.class.getClassLoader()
.getResourceAsStream("org/flywaydb/community/database/tibero/version.txt")),
StandardCharsets.UTF_8);
} catch (IOException e) {
throw new FlywayException("Unable to read extension version: " + e.getMessage(), e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.flywaydb.community.database.tibero;

import java.sql.SQLException;
import org.flywaydb.core.internal.database.base.Connection;
import org.flywaydb.core.internal.database.base.Schema;

public class TiberoConnection extends Connection<TiberoDatabase> {

protected TiberoConnection(TiberoDatabase database, java.sql.Connection connection) {
super(database, connection);
}

@Override
protected String getCurrentSchemaNameOrSearchPath() throws SQLException {
return jdbcTemplate.queryForString("SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL");
}

@Override
public void doChangeCurrentSchemaOrSearchPathTo(String schema) throws SQLException {
jdbcTemplate.execute("ALTER SESSION SET CURRENT_SCHEMA=" + database.quote(schema));
}

@Override
public Schema doGetCurrentSchema() throws SQLException {
String currentSchema = getCurrentSchemaNameOrSearchPath();

return getSchema(currentSchema);
}

@Override
public Schema getSchema(String name) {
return new TiberoSchema(jdbcTemplate, database, name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package org.flywaydb.community.database.tibero;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.extensibility.Tier;
import org.flywaydb.core.internal.database.base.Database;
import org.flywaydb.core.internal.database.base.Table;
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
import org.flywaydb.core.internal.jdbc.StatementInterceptor;
import org.flywaydb.core.internal.util.StringUtils;

public class TiberoDatabase extends Database<TiberoConnection> {

public TiberoDatabase(Configuration configuration, JdbcConnectionFactory jdbcConnectionFactory,
StatementInterceptor statementInterceptor) {
super(configuration, jdbcConnectionFactory, statementInterceptor);
}

public static void enableTiberoTNSNameSupport() {
String tiberoAdminEnvVar = System.getenv("TIBERO_ADMIN");
String tiberoAdminSysProp = System.getProperty("TIBERO_NET_ADMIN");
if (StringUtils.hasLength(tiberoAdminEnvVar) && tiberoAdminSysProp == null) {
System.setProperty("TIBERO_NET_ADMIN", tiberoAdminEnvVar);
}
}

@Override
protected TiberoConnection doGetConnection(Connection connection) {
return new TiberoConnection(this, connection);
}

@Override
protected String doGetCurrentUser() throws SQLException {
return getMainConnection().getJdbcTemplate().queryForString("SELECT USER FROM DUAL");
}

@Override
public void ensureSupported(Configuration configuration) {
ensureDatabaseIsRecentEnough("7.0");
ensureDatabaseNotOlderThanOtherwiseRecommendUpgradeToFlywayEdition("7.0", Tier.PREMIUM, configuration);
recommendFlywayUpgradeIfNecessaryForMajorVersion("21.3");
}

@Override
public boolean supportsDdlTransactions() {
return false;
}

@Override
public String getBooleanTrue() {
return "1";
}

@Override
public String getBooleanFalse() {
return "0";
}

@Override
public boolean catalogIsSchema() {
return false;
}

@Override
public String getRawCreateScript(Table table, boolean baseline) {
String tablespace = configuration.getTablespace() == null
? ""
: " TABLESPACE \"" + configuration.getTablespace() + "\"";

return "CREATE TABLE " + table + " (\n" +
" \"installed_rank\" NUMBER NOT NULL,\n" +
" \"version\" VARCHAR2(50),\n" +
" \"description\" VARCHAR2(200) NOT NULL,\n" +
" \"type\" VARCHAR2(20) NOT NULL,\n" +
" \"script\" VARCHAR2(1000) NOT NULL,\n" +
" \"checksum\" NUMBER,\n" +
" \"installed_by\" VARCHAR2(100) NOT NULL,\n" +
" \"installed_on\" TIMESTAMP DEFAULT SYSDATE NOT NULL,\n" +
" \"execution_time\" NUMBER NOT NULL,\n" +
" \"success\" NUMBER(1) NOT NULL,\n" +
" CONSTRAINT \"" + table.getName() + "_pk\" PRIMARY KEY (\"installed_rank\")\n" +
")" + tablespace + ";\n" +
(baseline ? getBaselineStatement(table) + ";\n" : "") +
"CREATE INDEX \"" + table.getSchema().getName() + "\".\"" + table.getName() + "_s_idx\" ON " + table
+ " (\"success\");\n";
}

boolean isXmlDbAvailable() throws SQLException {
return isDataDictViewAccessible("ALL_XML_TABLES");
}

boolean isPrivOrRoleGranted(String name) throws SQLException {
return queryReturnsRows("SELECT 1 FROM SESSION_PRIVS WHERE PRIVILEGE = ? UNION ALL " +
"SELECT 1 FROM SESSION_ROLES WHERE ROLE = ?", name, name);
}

boolean queryReturnsRows(String query, String... params) throws SQLException {
return getMainConnection().getJdbcTemplate()
.queryForBoolean("SELECT CASE WHEN EXISTS(" + query + ") THEN 1 ELSE 0 END FROM DUAL", params);
}

private boolean isDataDictViewAccessible(String owner, String name) throws SQLException {
return queryReturnsRows("SELECT * FROM DBA_TAB_PRIVS WHERE OWNER = ? AND TABLE_NAME = ?" +
" AND PRIVILEGE = 'SELECT'", owner, name);
}

boolean isDataDictViewAccessible(String name) throws SQLException {
return isDataDictViewAccessible("SYS", name);
}

Set<String> getSystemSchemas() throws SQLException {

Set<String> result = new HashSet<>(Arrays.asList(
"SYS",
"SYSCAT",
"OUTLN",
"SYSGIS"
));

result.addAll(getMainConnection().getJdbcTemplate().queryForStringList(
"SELECT USERNAME FROM DBA_USERS WHERE USERNAME LIKE 'SYS%'"
));

return result;
}

boolean isFlashbackDataArchiveAvailable(String schemaName) throws SQLException {
String paramQuery = "SELECT COUNT(*) FROM V$PARAMETERS WHERE NAME LIKE '%FLASHBACK%' AND VALUE IS NOT NULL AND (LENGTH(TRIM(VALUE)) > 0 OR VALUE != '0')";
int paramCount = getMainConnection().getJdbcTemplate().queryForInt(paramQuery);

if (paramCount == 0) {
return false;
}

String destQuery = "SELECT VALUE FROM V$PARAMETERS WHERE NAME = 'FLASHBACK_LOG_ARCHIVE_DEST'";
String flashbackDest = getMainConnection().getJdbcTemplate().queryForString(destQuery);

if (flashbackDest == null || flashbackDest.trim().isEmpty()) {
return false;
}

String logModeQuery = "SELECT LOG_MODE FROM V$DATABASE";
String logMode = getMainConnection().getJdbcTemplate().queryForString(logModeQuery);

if (!"ARCHIVELOG".equalsIgnoreCase(logMode)) {
return false;
}

String tablespaceQuery = "SELECT COUNT(*) FROM DBA_USERS u JOIN V$TABLESPACE t ON u.DEFAULT_TABLESPACE = t.NAME WHERE u.USERNAME = ? AND t.FLASHBACK_ON = 'YES'";
int flashbackOnCount = getMainConnection().getJdbcTemplate()
.queryForInt(tablespaceQuery, schemaName.toUpperCase());

if (flashbackOnCount == 0) {
return false;
}

String privilegeQuery = "SELECT COUNT(*) FROM DBA_SYS_PRIVS WHERE GRANTEE = ? AND (PRIVILEGE = 'FLASHBACK ANY TABLE' OR PRIVILEGE = 'FLASHBACK OBJECT')";
int privilegeCount = getMainConnection().getJdbcTemplate()
.queryForInt(privilegeQuery, schemaName.toUpperCase());

return privilegeCount != 0;
}

String dbaOrAll(String baseName) throws SQLException {
return isPrivOrRoleGranted("SELECT ANY DICTIONARY") || isDataDictViewAccessible("DBA_" + baseName)
? "DBA_" + baseName
: "ALL_" + baseName;
}

boolean isLocatorAvailable() throws SQLException {
return isDataDictViewAccessible("SYSGIS", "ALL_GEOMETRY_COLUMNS");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.flywaydb.community.database.tibero;

import java.sql.Connection;
import java.sql.Types;
import org.flywaydb.core.api.ResourceProvider;
import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.internal.database.base.BaseDatabaseType;
import org.flywaydb.core.internal.database.base.CommunityDatabaseType;
import org.flywaydb.core.internal.database.base.Database;
import org.flywaydb.core.internal.jdbc.JdbcConnectionFactory;
import org.flywaydb.core.internal.jdbc.StatementInterceptor;
import org.flywaydb.core.internal.parser.Parser;
import org.flywaydb.core.internal.parser.ParsingContext;

public class TiberoDatabaseType extends BaseDatabaseType implements CommunityDatabaseType {

@Override
public String getName() {
return "Tibero";
}

@Override
public int getNullType() {
return Types.VARCHAR;
}

@Override
public boolean handlesJDBCUrl(String url) {
return url.startsWith("jdbc:tibero");
}

@Override
public String getDriverClass(String url, ClassLoader classLoader) {
return "com.tmax.tibero.jdbc.TbDriver";
}

@Override
public boolean handlesDatabaseProductNameAndVersion(String databaseProductName,
String databaseProductVersion, Connection connection) {
return true;
}

@Override
public Database createDatabase(Configuration configuration,
JdbcConnectionFactory jdbcConnectionFactory, StatementInterceptor statementInterceptor) {
TiberoDatabase.enableTiberoTNSNameSupport();

return new TiberoDatabase(configuration, jdbcConnectionFactory, statementInterceptor);
}

@Override
public Parser createParser(Configuration configuration, ResourceProvider resourceProvider,
ParsingContext parsingContext) {
return new TiberoParser(configuration, parsingContext, 3);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.flywaydb.community.database.tibero;

import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.internal.parser.Parser;
import org.flywaydb.core.internal.parser.ParsingContext;

public class TiberoParser extends Parser {

protected TiberoParser(Configuration configuration, ParsingContext parsingContext, int peekDepth) {
super(configuration, parsingContext, peekDepth);
}
}
Loading