Skip to content
Snippets Groups Projects
Unverified Commit 2bb0c1e3 authored by Martin Weise's avatar Martin Weise
Browse files

Added the transaction check and rollback

parent 773cff0d
Branches
Tags
2 merge requests!129New module for citation as they occur multiple,!121Modified logging, modified logging level, modified flasgger endpoint
...@@ -43,16 +43,17 @@ public class ColumnCreateDto { ...@@ -43,16 +43,17 @@ public class ColumnCreateDto {
private Boolean unique; private Boolean unique;
@JsonProperty("check_expression") @JsonProperty("check_expression")
@Schema(description = "check constraint", example = "id > 0")
private String checkExpression; private String checkExpression;
@JsonProperty("foreign_key") @JsonProperty("foreign_key")
private String foreignKey = null; private String foreignKey = null;
@Parameter(description = "foreign key reference, only considered when foreignKey != null") @Schema(description = "foreign key reference, only considered when foreignKey != null")
private String references = null; private String references = null;
@JsonProperty("enum_values") @JsonProperty("enum_values")
@Parameter(description = "enum values, only considered when type = ENUM") @Schema(description = "enum values, only considered when type = ENUM")
private String[] enumValues = null; private String[] enumValues = null;
} }
...@@ -3,6 +3,8 @@ package at.tuwien; ...@@ -3,6 +3,8 @@ package at.tuwien;
import at.tuwien.api.database.query.QueryBriefDto; import at.tuwien.api.database.query.QueryBriefDto;
import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryDto;
import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableCreateDto;
import at.tuwien.api.database.table.columns.ColumnCreateDto;
import at.tuwien.api.database.table.columns.ColumnTypeDto;
import at.tuwien.api.user.UserDto; import at.tuwien.api.user.UserDto;
import at.tuwien.entities.container.image.*; import at.tuwien.entities.container.image.*;
import at.tuwien.entities.database.table.columns.concepts.Concept; import at.tuwien.entities.database.table.columns.concepts.Concept;
...@@ -324,13 +326,15 @@ public abstract class BaseUnitTest { ...@@ -324,13 +326,15 @@ public abstract class BaseUnitTest {
public final static String COLUMN_4_1_NAME = "id"; public final static String COLUMN_4_1_NAME = "id";
public final static String COLUMN_4_1_INTERNAL_NAME = "id"; public final static String COLUMN_4_1_INTERNAL_NAME = "id";
public final static TableColumnType COLUMN_4_1_TYPE = TableColumnType.NUMBER; public final static TableColumnType COLUMN_4_1_TYPE = TableColumnType.NUMBER;
public final static ColumnTypeDto COLUMN_4_1_TYPE_DTO = ColumnTypeDto.NUMBER;
public final static Long COLUMN_4_1_DATE_FORMAT = null; public final static Long COLUMN_4_1_DATE_FORMAT = null;
public final static Boolean COLUMN_4_1_NULL = false; public final static Boolean COLUMN_4_1_NULL = false;
public final static Boolean COLUMN_4_1_UNIQUE = true; public final static Boolean COLUMN_4_1_UNIQUE = true;
public final static Boolean COLUMN_4_1_AUTO_GENERATED = true; public final static Boolean COLUMN_4_1_AUTO_GENERATED = true;
public final static String COLUMN_4_1_FOREIGN_KEY = null; public final static String COLUMN_4_1_FOREIGN_KEY = null;
public final static String COLUMN_4_1_CHECK = null; public final static String COLUMN_4_1_REFERENCES = null;
public final static List<String> COLUMN_4_1_ENUM_VALUES = null; public final static List<String> COLUMN_4_1_ENUM_VALUES = null;
public final static String[] COLUMN_4_1_ENUM_VALUES_ARRAY = null;
public final static Long COLUMN_4_2_ID = 10L; public final static Long COLUMN_4_2_ID = 10L;
public final static Integer COLUMN_4_2_ORDINALPOS = 1; public final static Integer COLUMN_4_2_ORDINALPOS = 1;
...@@ -338,13 +342,16 @@ public abstract class BaseUnitTest { ...@@ -338,13 +342,16 @@ public abstract class BaseUnitTest {
public final static String COLUMN_4_2_NAME = "Animal Name"; public final static String COLUMN_4_2_NAME = "Animal Name";
public final static String COLUMN_4_2_INTERNAL_NAME = "animal_name"; public final static String COLUMN_4_2_INTERNAL_NAME = "animal_name";
public final static TableColumnType COLUMN_4_2_TYPE = TableColumnType.STRING; public final static TableColumnType COLUMN_4_2_TYPE = TableColumnType.STRING;
public final static ColumnTypeDto COLUMN_4_2_TYPE_DTO = ColumnTypeDto.STRING;
public final static Long COLUMN_4_2_DATE_FORMAT = null; public final static Long COLUMN_4_2_DATE_FORMAT = null;
public final static Boolean COLUMN_4_2_NULL = true; public final static Boolean COLUMN_4_2_NULL = true;
public final static Boolean COLUMN_4_2_UNIQUE = false; public final static Boolean COLUMN_4_2_UNIQUE = false;
public final static Boolean COLUMN_4_2_AUTO_GENERATED = false; public final static Boolean COLUMN_4_2_AUTO_GENERATED = false;
public final static String COLUMN_4_2_FOREIGN_KEY = null; public final static String COLUMN_4_2_FOREIGN_KEY = null;
public final static String COLUMN_4_2_REFERENCES = null;
public final static String COLUMN_4_2_CHECK = null; public final static String COLUMN_4_2_CHECK = null;
public final static List<String> COLUMN_4_2_ENUM_VALUES = null; public final static List<String> COLUMN_4_2_ENUM_VALUES = null;
public final static String[] COLUMN_4_2_ENUM_VALUES_ARRAY = null;
public final static Long COLUMN_4_3_ID = 11L; public final static Long COLUMN_4_3_ID = 11L;
public final static Integer COLUMN_4_3_ORDINALPOS = 2; public final static Integer COLUMN_4_3_ORDINALPOS = 2;
...@@ -1486,6 +1493,7 @@ public abstract class BaseUnitTest { ...@@ -1486,6 +1493,7 @@ public abstract class BaseUnitTest {
.autoGenerated(COLUMN_4_1_AUTO_GENERATED) .autoGenerated(COLUMN_4_1_AUTO_GENERATED)
.isPrimaryKey(COLUMN_4_1_PRIMARY) .isPrimaryKey(COLUMN_4_1_PRIMARY)
.enumValues(COLUMN_4_1_ENUM_VALUES) .enumValues(COLUMN_4_1_ENUM_VALUES)
.references(COLUMN_4_1_REFERENCES)
.build(), .build(),
TableColumn.builder() TableColumn.builder()
.id(COLUMN_4_2_ID) .id(COLUMN_4_2_ID)
...@@ -1871,11 +1879,45 @@ public abstract class BaseUnitTest { ...@@ -1871,11 +1879,45 @@ public abstract class BaseUnitTest {
.build(); .build();
public final static TableCreateDto TABLE_3_CREATE_DTO = TableCreateDto.builder() public final static TableCreateDto TABLE_3_CREATE_DTO = TableCreateDto.builder()
.name(TABLE_5_NAME) .name(TABLE_3_NAME)
.description(TABLE_5_DESCRIPTION) .description(TABLE_3_DESCRIPTION)
.columns(List.of()) .columns(List.of())
.build(); .build();
public final static List<ColumnCreateDto> TABLE_4_COLUMNS_INVALID_CREATE = List.of(ColumnCreateDto.builder()
.name(COLUMN_4_2_NAME)
.type(COLUMN_4_2_TYPE_DTO)
.dfid(COLUMN_4_2_DATE_FORMAT)
.nullAllowed(COLUMN_4_2_NULL)
.unique(COLUMN_4_2_UNIQUE)
.primaryKey(COLUMN_4_2_PRIMARY)
.enumValues(COLUMN_4_2_ENUM_VALUES_ARRAY)
.foreignKey("somecolumn")
.references("sometable")
.build());
public final static List<ColumnCreateDto> TABLE_4_COLUMNS_CREATE = List.of(ColumnCreateDto.builder()
.name(COLUMN_4_2_NAME)
.type(COLUMN_4_2_TYPE_DTO)
.dfid(COLUMN_4_2_DATE_FORMAT)
.nullAllowed(COLUMN_4_2_NULL)
.unique(COLUMN_4_2_UNIQUE)
.primaryKey(COLUMN_4_2_PRIMARY)
.enumValues(COLUMN_4_2_ENUM_VALUES_ARRAY)
.build());
public final static TableCreateDto TABLE_4_CREATE_DTO = TableCreateDto.builder()
.name(TABLE_4_NAME)
.description(TABLE_4_DESCRIPTION)
.columns(TABLE_4_COLUMNS_CREATE)
.build();
public final static TableCreateDto TABLE_4_INVALID_CREATE_DTO = TableCreateDto.builder()
.name(TABLE_4_NAME)
.description(TABLE_4_DESCRIPTION)
.columns(TABLE_4_COLUMNS_INVALID_CREATE)
.build();
public final static Table TABLE_4 = Table.builder() public final static Table TABLE_4 = Table.builder()
.id(TABLE_4_ID) .id(TABLE_4_ID)
.created(Instant.now()) .created(Instant.now())
......
...@@ -26,6 +26,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; ...@@ -26,6 +26,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.File; import java.io.File;
import java.security.Principal; import java.security.Principal;
import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -231,6 +232,27 @@ public class TableServiceIntegrationTest extends BaseUnitTest { ...@@ -231,6 +232,27 @@ public class TableServiceIntegrationTest extends BaseUnitTest {
tableService.createTable(CONTAINER_1_ID, DATABASE_1_ID, TABLE_3_CREATE_DTO, principal); tableService.createTable(CONTAINER_1_ID, DATABASE_1_ID, TABLE_3_CREATE_DTO, principal);
} }
@Test
public void create_failedBefore_succeeds() throws UserNotFoundException, TableMalformedException, QueryMalformedException,
DatabaseNotFoundException, ImageNotSupportedException, TableNameExistsException,
ContainerNotFoundException {
final Principal principal = new BasicUserPrincipal(USER_1_USERNAME);
/* mock */
when(tableidxRepository.save(any(Table.class)))
.thenReturn(TABLE_1);
when(tableColumnidxRepository.saveAll(anyList()))
.thenReturn(List.of());
/* test */
try {
tableService.createTable(CONTAINER_1_ID, DATABASE_1_ID, TABLE_4_INVALID_CREATE_DTO, principal);
} catch (TableMalformedException e) {
/* ignore */
}
tableService.createTable(CONTAINER_1_ID, DATABASE_1_ID, TABLE_4_CREATE_DTO, principal);
}
@Test @Test
public void delete_succeeds() throws TableMalformedException, QueryMalformedException, DatabaseNotFoundException, public void delete_succeeds() throws TableMalformedException, QueryMalformedException, DatabaseNotFoundException,
ImageNotSupportedException, ContainerNotFoundException, TableNotFoundException, DataProcessingException { ImageNotSupportedException, ContainerNotFoundException, TableNotFoundException, DataProcessingException {
......
...@@ -20,4 +20,4 @@ spring.jpa.properties.hibernate.hbm2ddl.schema_filter_provider=at.tuwien.hiberna ...@@ -20,4 +20,4 @@ spring.jpa.properties.hibernate.hbm2ddl.schema_filter_provider=at.tuwien.hiberna
# additional logging # additional logging
logging.level.org.hibernate.SQL=debug logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type=trace logging.level.org.hibernate.type=warn
\ No newline at end of file \ No newline at end of file
...@@ -297,6 +297,25 @@ public interface TableMapper { ...@@ -297,6 +297,25 @@ public interface TableMapper {
} }
} }
default PreparedStatement tableToDropSequenceRawQuery(Connection connection, Database database, TableCreateDto data)
throws ImageNotSupportedException, QueryMalformedException {
if (!database.getContainer().getImage().getRepository().equals("mariadb")) {
log.error("Currently only MariaDB is supported");
throw new ImageNotSupportedException("Currently only MariaDB is supported");
}
final StringBuilder statement = new StringBuilder("DROP SEQUENCE `")
.append(tableCreateDtoToSequenceName(data))
.append("`;");
try {
final PreparedStatement pstmt = connection.prepareStatement(statement.toString());
log.trace("prepared drop sequence statement {}", statement);
return pstmt;
} catch (SQLException e) {
log.error("Failed to prepare statement {}, reason: {}", statement, e.getMessage());
throw new QueryMalformedException("Failed to prepare statement", e);
}
}
default PreparedStatement tableToCreateHistoryViewRawQuery(Connection connection, Table data) throws QueryMalformedException { default PreparedStatement tableToCreateHistoryViewRawQuery(Connection connection, Table data) throws QueryMalformedException {
final StringBuilder statement = new StringBuilder("CREATE VIEW `hs_") final StringBuilder statement = new StringBuilder("CREATE VIEW `hs_")
.append(data.getInternalName()) .append(data.getInternalName())
......
...@@ -114,8 +114,8 @@ public class TableServiceImpl extends HibernateConnector implements TableService ...@@ -114,8 +114,8 @@ public class TableServiceImpl extends HibernateConnector implements TableService
final Optional<Table> optional = tableRepository.findByDatabaseAndInternalName(database, final Optional<Table> optional = tableRepository.findByDatabaseAndInternalName(database,
tableMapper.nameToInternalName(createDto.getName())); tableMapper.nameToInternalName(createDto.getName()));
if (optional.isPresent()) { if (optional.isPresent()) {
log.error("Table name exists"); log.error("Table '{}' exists in metadata database", optional.get().getInternalName());
throw new TableNameExistsException("Table name exists"); throw new TableNameExistsException("Table exists in metadata database");
} }
/* run query */ /* run query */
final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(), database.getContainer(), database); final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(), database.getContainer(), database);
...@@ -132,7 +132,15 @@ public class TableServiceImpl extends HibernateConnector implements TableService ...@@ -132,7 +132,15 @@ public class TableServiceImpl extends HibernateConnector implements TableService
final PreparedStatement preparedStatement11 = query.getPreparedStatement(); final PreparedStatement preparedStatement11 = query.getPreparedStatement();
preparedStatement11.executeUpdate(); preparedStatement11.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
log.error("failed to create table, reason: {}", e.getMessage()); try {
final Connection connection = dataSource.getConnection();
final PreparedStatement preparedStatement11 = tableMapper.tableToDropSequenceRawQuery(connection, database, createDto);
preparedStatement11.executeUpdate();
log.debug("successfully rolled back creation of id sequence");
} catch (SQLException ex) {
log.error("Failed to rollback creation of id sequence");
}
log.error("Failed to create table, reason: {}", e.getMessage());
throw new TableMalformedException("Failed to create table", e); throw new TableMalformedException("Failed to create table", e);
} finally { } finally {
dataSource.close(); dataSource.close();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment