Skip to content
Snippets Groups Projects
Commit 25ce76c7 authored by Martin Weise's avatar Martin Weise
Browse files

Dev

parent 3505162c
Branches
Tags
2 merge requests!250Master,!246Dev
Showing
with 903 additions and 782 deletions
...@@ -71,6 +71,10 @@ execution to the raw data. Any stale queries (query that have been executed by u ...@@ -71,6 +71,10 @@ execution to the raw data. Any stale queries (query that have been executed by u
periodically being deleted from the query store based on the `DELETE_STALE_QUERIES_RATE` environment variable (defaults periodically being deleted from the query store based on the `DELETE_STALE_QUERIES_RATE` environment variable (defaults
to 60 seconds). to 60 seconds).
Executing SQL queries through the Query Endpoint must fulfill some restrictions:
* The SQL query does not contain at semicolon `;`
### Semantics ### Semantics
The service provides metadata to the table columns in the [Metadata Database](../system-databases-metadata) from The service provides metadata to the table columns in the [Metadata Database](../system-databases-metadata) from
......
...@@ -71,6 +71,18 @@ build-docker: ...@@ -71,6 +71,18 @@ build-docker:
- "docker build -t dbrepo-data-service:build --target build dbrepo-data-service" - "docker build -t dbrepo-data-service:build --target build dbrepo-data-service"
- "docker compose build --parallel" - "docker compose build --parallel"
build-helm:
image: docker.io/docker:24-dind
stage: build
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY_URL
script:
- apk add sed helm curl
- 'sed -i -e "s/^version:.*/version: \"${CHART_VERSION}\"/g" ./helm-charts/dbrepo/Chart.yaml'
- 'sed -i -e "s/^appVersion:.*/appVersion: \"${APP_VERSION}\"/g" ./helm-charts/dbrepo/Chart.yaml'
- find ./helm-charts -type f -exec sed -i -e "s/__CHARTVERSION__/${CHART_VERSION}/g" {} \;
- helm package ./helm-charts/dbrepo --destination ./build
test-metadata-service: test-metadata-service:
image: maven:3-openjdk-17 image: maven:3-openjdk-17
stage: test stage: test
...@@ -119,12 +131,13 @@ test-analyse-service: ...@@ -119,12 +131,13 @@ test-analyse-service:
script: script:
- "pip install pipenv" - "pip install pipenv"
- "pipenv install gunicorn && pipenv install --dev --system --deploy" - "pipenv install gunicorn && pipenv install --dev --system --deploy"
- "cd ./dbrepo-analyse-service/ && coverage run -m pytest test/test_determine_dt.py test/test_determine_pk.py test/test_determine_stats.py --junitxml=report.xml && coverage html && coverage report > ./coverage.txt" - cd ./dbrepo-analyse-service/ && coverage run -m pytest test/test_determine_dt.py test/test_determine_pk.py test/test_s3_client.py --junitxml=report.xml && coverage html --omit="test/*" && coverage report --omit="test/*" > ./coverage.txt
- "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'"
artifacts: artifacts:
when: always when: always
paths: paths:
- ./dbrepo-analyse-service/report.xml - ./dbrepo-analyse-service/report.xml
- ./dbrepo-analyse-service/coverage.txt
expire_in: 1 days expire_in: 1 days
reports: reports:
junit: ./dbrepo-analyse-service/report.xml junit: ./dbrepo-analyse-service/report.xml
......
[pytest] [pytest]
log_cli = 1 log_cli = 1
log_level = info log_level = info
log_disable = main
\ No newline at end of file
...@@ -139,6 +139,7 @@ ...@@ -139,6 +139,7 @@
versioned boolean not null default true, versioned boolean not null default true,
created_by character varying(36) NOT NULL, created_by character varying(36) NOT NULL,
owned_by character varying(36) NOT NULL, owned_by character varying(36) NOT NULL,
processed_constraints BOOLEAN NOT NULL DEFAULT false,
last_modified timestamp, last_modified timestamp,
PRIMARY KEY (ID), PRIMARY KEY (ID),
FOREIGN KEY (tDBID) REFERENCES mdb_databases (id), FOREIGN KEY (tDBID) REFERENCES mdb_databases (id),
...@@ -153,7 +154,6 @@ ...@@ -153,7 +154,6 @@
dfID BIGINT, dfID BIGINT,
cName VARCHAR(100), cName VARCHAR(100),
internal_name VARCHAR(100) NOT NULL, internal_name VARCHAR(100) NOT NULL,
alias VARCHAR(100),
Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'),
length BIGINT NULL, length BIGINT NULL,
ordinal_position INTEGER NOT NULL, ordinal_position INTEGER NOT NULL,
...@@ -220,6 +220,7 @@ ...@@ -220,6 +220,7 @@
fkid BIGINT NOT NULL AUTO_INCREMENT, fkid BIGINT NOT NULL AUTO_INCREMENT,
tid BIGINT NOT NULL, tid BIGINT NOT NULL,
rtid BIGINT NOT NULL, rtid BIGINT NOT NULL,
name VARCHAR(255) NOT NULL,
on_update VARCHAR(50) NULL, on_update VARCHAR(50) NULL,
on_delete VARCHAR(50) NULL, on_delete VARCHAR(50) NULL,
position INT NULL, position INT NULL,
...@@ -243,6 +244,7 @@ ...@@ -243,6 +244,7 @@
CREATE TABLE IF NOT EXISTS `mdb_constraints_unique` CREATE TABLE IF NOT EXISTS `mdb_constraints_unique`
( (
uid BIGINT NOT NULL AUTO_INCREMENT, uid BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
tid BIGINT NOT NULL, tid BIGINT NOT NULL,
position INT NULL, position INT NULL,
PRIMARY KEY (uid), PRIMARY KEY (uid),
...@@ -358,7 +360,8 @@ ...@@ -358,7 +360,8 @@
id BIGINT NOT NULL AUTO_INCREMENT, id BIGINT NOT NULL AUTO_INCREMENT,
cid BIGINT NOT NULL, cid BIGINT NOT NULL,
vid BIGINT NOT NULL, vid BIGINT NOT NULL,
position INTEGER NULL, alias VARCHAR(100),
ordinal_position INTEGER,
PRIMARY KEY (id), PRIMARY KEY (id),
FOREIGN KEY (vid) REFERENCES mdb_view (id), FOREIGN KEY (vid) REFERENCES mdb_view (id),
FOREIGN KEY (cid) REFERENCES mdb_columns (ID) FOREIGN KEY (cid) REFERENCES mdb_columns (ID)
......
...@@ -43,4 +43,8 @@ public class ImportDto { ...@@ -43,4 +43,8 @@ public class ImportDto {
@Schema(example = "\"") @Schema(example = "\"")
private Character quote; private Character quote;
@JsonProperty("line_termination")
@Schema(example = "\\r\\n")
private String lineTermination;
} }
...@@ -19,6 +19,8 @@ import java.util.List; ...@@ -19,6 +19,8 @@ import java.util.List;
@ToString @ToString
public class ForeignKeyDto { public class ForeignKeyDto {
private String name;
@org.springframework.data.annotation.Transient @org.springframework.data.annotation.Transient
private List<ColumnDto> columns; private List<ColumnDto> columns;
......
...@@ -111,20 +111,13 @@ public class View { ...@@ -111,20 +111,13 @@ public class View {
return this.internalName.equals(table.getName().replace("`", "")); return this.internalName.equals(table.getName().replace("`", ""));
} }
/**
* Cascade cannot be CascadeType.PERSIST since columns already exist
*/
@ToString.Exclude @ToString.Exclude
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
@JoinTable(name = "mdb_view_columns", @JoinColumns({
inverseJoinColumns = { @JoinColumn(name = "vid", referencedColumnName = "id", updatable = false)
@JoinColumn(name = "cid", referencedColumnName = "id"),
},
joinColumns = {
@JoinColumn(name = "vid", referencedColumnName = "id"),
}) })
@OrderColumn(name = "position") @OrderColumn(name = "ordinalPosition")
private List<TableColumn> columns; private List<ViewColumn> columns;
@CreatedDate @CreatedDate
@Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP default NOW()") @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP default NOW()")
......
package at.tuwien.entities.database;
import at.tuwien.entities.database.table.columns.TableColumn;
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import jakarta.persistence.*;
@Data
@Entity
@Builder(toBuilder = true)
@ToString
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@jakarta.persistence.Table(name = "mdb_view_columns", uniqueConstraints = {
@UniqueConstraint(columnNames = {"cid", "vid"})
})
public class ViewColumn implements Comparable<ViewColumn> {
@Id
@EqualsAndHashCode.Include
@GeneratedValue(generator = "view-columns-sequence")
@GenericGenerator(name = "view-columns-sequence", strategy = "increment")
@Column(updatable = false, nullable = false)
private Long id;
@Column(updatable = false)
private String alias;
@Column(nullable = false)
private Integer ordinalPosition;
@ToString.Exclude
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
@JoinColumns({
@JoinColumn(name = "vid", referencedColumnName = "id", updatable = false)
})
private View view;
@ToString.Exclude
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE})
@JoinColumns({
@JoinColumn(name = "cid", referencedColumnName = "id", updatable = false)
})
private TableColumn column;
@Override
public int compareTo(ViewColumn tableColumn) {
return Integer.compare(this.ordinalPosition, tableColumn.getOrdinalPosition());
}
}
...@@ -132,6 +132,9 @@ public class Table { ...@@ -132,6 +132,9 @@ public class Table {
@Column(columnDefinition = "TIMESTAMP") @Column(columnDefinition = "TIMESTAMP")
private Instant lastModified; private Instant lastModified;
@Column(name = "processed_constraints", nullable = false)
private Boolean processedConstraints;
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) { if (o == this) {
......
...@@ -73,7 +73,7 @@ public class TableColumn implements Comparable<TableColumn> { ...@@ -73,7 +73,7 @@ public class TableColumn implements Comparable<TableColumn> {
@Column @Column
private Long indexLength; private Long indexLength;
@Column @Transient
private String alias; private String alias;
@Column(name = "datatype", nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')") @Column(name = "datatype", nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')")
......
...@@ -26,6 +26,9 @@ public class ForeignKey { ...@@ -26,6 +26,9 @@ public class ForeignKey {
@Column(updatable = false, nullable = false) @Column(updatable = false, nullable = false)
private Long fkid; private Long fkid;
@Column(updatable = false, nullable = false)
private String name;
@ToString.Exclude @ToString.Exclude
@org.springframework.data.annotation.Transient @org.springframework.data.annotation.Transient
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
......
...@@ -27,6 +27,9 @@ public class Unique { ...@@ -27,6 +27,9 @@ public class Unique {
@Column(updatable = false, nullable = false) @Column(updatable = false, nullable = false)
private Long uid; private Long uid;
@Column(updatable = false, nullable = false)
private String name;
@ToString.Exclude @ToString.Exclude
@org.springframework.data.annotation.Transient @org.springframework.data.annotation.Transient
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
......
...@@ -117,7 +117,7 @@ public interface DatabaseMapper { ...@@ -117,7 +117,7 @@ public interface DatabaseMapper {
default PreparedStatement databaseToDatabaseMetadata(Connection connection, Database database) throws QueryMalformedException { default PreparedStatement databaseToDatabaseMetadata(Connection connection, Database database) throws QueryMalformedException {
final StringBuilder statement = new StringBuilder("SELECT t.`TABLE_NAME`, t.`TABLE_TYPE`, t.`TABLE_ROWS`, t.`AVG_ROW_LENGTH`, t.`DATA_LENGTH`, t.`MAX_DATA_LENGTH`, COALESCE(t.`CREATE_TIME`, NOW()) as `CREATE_TIME`, t.`UPDATE_TIME`, v.`VIEW_DEFINITION` FROM information_schema.TABLES t LEFT JOIN information_schema.VIEWS v ON t.`TABLE_NAME` = v.`TABLE_NAME` WHERE t.`TABLE_SCHEMA` = '") final StringBuilder statement = new StringBuilder("SELECT t.`TABLE_NAME`, t.`TABLE_TYPE`, t.`TABLE_ROWS`, t.`AVG_ROW_LENGTH`, t.`DATA_LENGTH`, t.`MAX_DATA_LENGTH`, COALESCE(t.`CREATE_TIME`, NOW()) as `CREATE_TIME`, t.`UPDATE_TIME`, v.`VIEW_DEFINITION` FROM information_schema.TABLES t LEFT JOIN information_schema.VIEWS v ON t.`TABLE_NAME` = v.`TABLE_NAME` WHERE t.`TABLE_SCHEMA` = '")
.append(database.getInternalName()) .append(database.getInternalName())
.append("' AND t.`TABLE_TYPE` IN ('BASE TABLE', 'SYSTEM VERSIONED', 'VIEW') AND t.`TABLE_NAME` NOT IN ('qs_queries', '_tmp') AND t.`TABLE_NAME` NOT LIKE 'hs_%' AND t.`TABLE_NAME` NOT LIKE '%_temporary'"); .append("' AND t.`TABLE_TYPE` IN ('BASE TABLE', 'SYSTEM VERSIONED', 'VIEW') AND t.`TABLE_NAME` != 'qs_queries' AND t.`TABLE_NAME` NOT LIKE 'hs_%'");
log.trace("statement={}", statement); log.trace("statement={}", statement);
try { try {
return connection.prepareStatement(statement.toString()); return connection.prepareStatement(statement.toString());
......
...@@ -85,7 +85,8 @@ public interface TableMapper { ...@@ -85,7 +85,8 @@ public interface TableMapper {
ColumnTypeDto columnTypeToColumnTypeDto(TableColumnType data); ColumnTypeDto columnTypeToColumnTypeDto(TableColumnType data);
@Mappings({ @Mappings({
@Mapping(target = "constraints", ignore = true) @Mapping(target = "constraints", ignore = true),
@Mapping(target = "processedConstraints", expression = "java(false)"),
}) })
Table tableCreateDtoToTable(TableCreateDto data); Table tableCreateDtoToTable(TableCreateDto data);
...@@ -124,6 +125,7 @@ public interface TableMapper { ...@@ -124,6 +125,7 @@ public interface TableMapper {
default Unique columnNameListToUnique(Table table, List<String> names) throws TableMalformedException { default Unique columnNameListToUnique(Table table, List<String> names) throws TableMalformedException {
return Unique.builder() return Unique.builder()
.table(table) .table(table)
.name("UK_" + String.join("_", names))
.columns(columnNameListToTableColumn(table, names)) .columns(columnNameListToTableColumn(table, names))
.build(); .build();
} }
...@@ -131,7 +133,7 @@ public interface TableMapper { ...@@ -131,7 +133,7 @@ public interface TableMapper {
ReferenceType referenceTypeDtoToReferenceType(ReferenceTypeDto dto); ReferenceType referenceTypeDtoToReferenceType(ReferenceTypeDto dto);
@Transactional(readOnly = true) @Transactional(readOnly = true)
default ForeignKey foreignKeyCreateDtoToForeignKey(Table table, ForeignKeyCreateDto data) throws TableMalformedException { default ForeignKey foreignKeyCreateDtoToForeignKey(Table table, ForeignKeyCreateDto data, Integer index) throws TableMalformedException {
final String referencedTableInternalName = nameToInternalName(data.getReferencedTable()); final String referencedTableInternalName = nameToInternalName(data.getReferencedTable());
final Optional<Table> optional = table.getDatabase() final Optional<Table> optional = table.getDatabase()
.getTables() .getTables()
...@@ -142,11 +144,13 @@ public interface TableMapper { ...@@ -142,11 +144,13 @@ public interface TableMapper {
log.error("Failed to find referenced table with internal name {} in database with id {}", referencedTableInternalName, table.getDatabase().getId()); log.error("Failed to find referenced table with internal name {} in database with id {}", referencedTableInternalName, table.getDatabase().getId());
throw new TableMalformedException("Failed to find referenced table with internal name " + referencedTableInternalName + " in database with id " + table.getDatabase().getId()); throw new TableMalformedException("Failed to find referenced table with internal name " + referencedTableInternalName + " in database with id " + table.getDatabase().getId());
} }
final ForeignKey.ForeignKeyBuilder builder = ForeignKey.builder() final ForeignKey foreignKey = ForeignKey.builder()
.name("fk_" + table.getInternalName() + "_" + (index + 1))
.table(table) .table(table)
.onUpdate(referenceTypeDtoToReferenceType(data.getOnUpdate())) .onUpdate(referenceTypeDtoToReferenceType(data.getOnUpdate()))
.onDelete(referenceTypeDtoToReferenceType(data.getOnDelete())) .onDelete(referenceTypeDtoToReferenceType(data.getOnDelete()))
.referencedTable(optional.get()); .referencedTable(optional.get())
.build();
final List<TableColumn> columns = columnNameListToTableColumn(table, data.getColumns()); final List<TableColumn> columns = columnNameListToTableColumn(table, data.getColumns());
final List<TableColumn> referencedColumns = columnNameListToTableColumn(optional.get(), data.getReferencedColumns()); final List<TableColumn> referencedColumns = columnNameListToTableColumn(optional.get(), data.getReferencedColumns());
if (columns.isEmpty()) { if (columns.isEmpty()) {
...@@ -158,7 +162,7 @@ public interface TableMapper { ...@@ -158,7 +162,7 @@ public interface TableMapper {
throw new TableMalformedException("There have to be equally as many columns and referenced columns in a foreign key"); throw new TableMalformedException("There have to be equally as many columns and referenced columns in a foreign key");
} }
final List<ForeignKeyReference> references = new ArrayList<>(); final List<ForeignKeyReference> references = new ArrayList<>();
final ForeignKey foreignKey = builder.references(references).build(); foreignKey.setReferences(references);
for (int i = 0; i < columns.size(); i++) { for (int i = 0; i < columns.size(); i++) {
TableColumn column = columns.get(i); TableColumn column = columns.get(i);
TableColumn referencedColumn = referencedColumns.get(i); TableColumn referencedColumn = referencedColumns.get(i);
...@@ -177,44 +181,43 @@ public interface TableMapper { ...@@ -177,44 +181,43 @@ public interface TableMapper {
if (data == null) { if (data == null) {
return null; return null;
} }
final ForeignKeyDto foreignKey = ForeignKeyDto.builder()
ForeignKeyDto dto = new ForeignKeyDto( .name(data.getName())
new ArrayList<>(), .columns(new LinkedList<>())
tableToTableBriefDto(data.getReferencedTable()), .referencedColumns(new LinkedList<>())
new ArrayList<>(), .referencedTable(tableToTableBriefDto(data.getReferencedTable()))
referenceTypeDtoToReferenceType(data.getOnUpdate()), .onDelete(referenceTypeDtoToReferenceType(data.getOnDelete()))
referenceTypeDtoToReferenceType(data.getOnDelete()) .onUpdate(referenceTypeDtoToReferenceType(data.getOnUpdate()))
); .build();
for (ForeignKeyReference reference : data.getReferences()) { for (ForeignKeyReference reference : data.getReferences()) {
dto.getColumns().add(tableColumnToColumnDto(reference.getColumn())); foreignKey.getColumns().add(tableColumnToColumnDto(reference.getColumn()));
dto.getReferencedColumns().add(tableColumnToColumnDto(reference.getReferencedColumn())); foreignKey.getReferencedColumns().add(tableColumnToColumnDto(reference.getReferencedColumn()));
} }
return dto; return foreignKey;
} }
@Transactional(readOnly = true)
default Constraints constraintsCreateDtoToConstraints(Table table, ConstraintsCreateDto data) default Constraints constraintsCreateDtoToConstraints(Table table, ConstraintsCreateDto data)
throws TableMalformedException { throws TableMalformedException {
if (data == null) { if (data == null) {
return null; return null;
} }
Constraints.ConstraintsBuilder builder = Constraints.builder(); final Constraints.ConstraintsBuilder builder = Constraints.builder();
if (data.getUniques() != null) { if (data.getUniques() != null) {
List<Unique> uniques = new ArrayList<>(); final List<Unique> uniques = new ArrayList<>();
for (List<String> columns : data.getUniques()) { for (List<String> columns : data.getUniques()) {
uniques.add(columnNameListToUnique(table, columns)); uniques.add(columnNameListToUnique(table, columns));
} }
builder.uniques(uniques); builder.uniques(uniques);
} }
if (data.getForeignKeys() != null) { if (data.getForeignKeys() != null) {
List<ForeignKey> foreignKeys = new ArrayList<>(); final List<ForeignKey> foreignKeys = new ArrayList<>();
for (ForeignKeyCreateDto foreignKeyData : data.getForeignKeys()) { for (int i = 0; i < data.getForeignKeys().size(); i++) {
foreignKeys.add(foreignKeyCreateDtoToForeignKey(table, foreignKeyData)); foreignKeys.add(foreignKeyCreateDtoToForeignKey(table, data.getForeignKeys().get(i), i));
} }
builder.foreignKeys(foreignKeys); builder.foreignKeys(foreignKeys);
} }
return builder.build(); return builder.build();
} }
...@@ -481,7 +484,7 @@ public interface TableMapper { ...@@ -481,7 +484,7 @@ public interface TableMapper {
} }
default PreparedStatement tableToCreateHistoryViewRawQuery(Connection connection, Table data) throws QueryMalformedException { default PreparedStatement tableToCreateHistoryViewRawQuery(Connection connection, Table data) throws QueryMalformedException {
final StringBuilder view = new StringBuilder("CREATE VIEW `hs_") final StringBuilder view = new StringBuilder("CREATE VIEW IF NOT EXISTS `hs_")
.append(data.getInternalName()) .append(data.getInternalName())
.append("` AS SELECT * FROM (SELECT ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at, COUNT(*) as total FROM `") .append("` AS SELECT * FROM (SELECT ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at, COUNT(*) as total FROM `")
.append(data.getInternalName()) .append(data.getInternalName())
...@@ -588,7 +591,10 @@ public interface TableMapper { ...@@ -588,7 +591,10 @@ public interface TableMapper {
.name(resultSet.getString(10)) .name(resultSet.getString(10))
.internalName(resultSet.getString(10)) .internalName(resultSet.getString(10))
.build(); .build();
if (resultSet.getString(5) != null) { /* fix boolean and set size for others */
if (resultSet.getString(8).equalsIgnoreCase("tinyint(1)")) {
column.setColumnType(TableColumnType.BOOL);
} else if (resultSet.getString(5) != null) {
column.setSize(resultSet.getLong(5)); column.setSize(resultSet.getLong(5));
} else if (resultSet.getString(6) != null) { } else if (resultSet.getString(6) != null) {
column.setSize(resultSet.getLong(6)); column.setSize(resultSet.getLong(6));
......
...@@ -4,16 +4,20 @@ import at.tuwien.api.database.ViewBriefDto; ...@@ -4,16 +4,20 @@ import at.tuwien.api.database.ViewBriefDto;
import at.tuwien.api.database.ViewCreateDto; import at.tuwien.api.database.ViewCreateDto;
import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.ViewDto;
import at.tuwien.entities.database.View; import at.tuwien.entities.database.View;
import at.tuwien.entities.database.ViewColumn;
import at.tuwien.entities.database.table.columns.TableColumn;
import at.tuwien.exception.QueryMalformedException; import at.tuwien.exception.QueryMalformedException;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.Mappings; import org.mapstruct.Mappings;
import org.mapstruct.Named; import org.mapstruct.Named;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.Normalizer; import java.text.Normalizer;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -45,15 +49,34 @@ public interface ViewMapper { ...@@ -45,15 +49,34 @@ public interface ViewMapper {
ViewBriefDto viewToViewBriefDto(View data); ViewBriefDto viewToViewBriefDto(View data);
@Transactional(readOnly = true)
default TableColumn viewColumnToTableColumn(ViewColumn data) {
return data.getColumn()
.toBuilder()
.alias(data.getAlias())
.build();
}
default List<ViewColumn> tableColumnsToViewColumns(View view, List<TableColumn> data) {
final int[] idx = new int[]{0};
return data.stream()
.map(c -> ViewColumn.builder()
.ordinalPosition(idx[0]++)
.column(c)
.view(view)
.alias(c.getAlias())
.build())
.toList();
}
default PreparedStatement viewToSelectAll(Connection connection, View view, Long page, Long size) throws QueryMalformedException { default PreparedStatement viewToSelectAll(Connection connection, View view, Long page, Long size) throws QueryMalformedException {
log.debug("mapping view query, view.query={}", view.getQuery()); log.debug("mapping view query, view.query={}, page={}, size={}", view.getQuery(), page, size);
final StringBuilder statement = new StringBuilder("SELECT "); final StringBuilder statement = new StringBuilder("SELECT ");
final int[] idx = new int[]{0}; final int[] idx = new int[]{0};
view.getColumns() view.getColumns()
.forEach(c -> statement.append(idx[0]++ > 0 ? "," : "") .forEach(c -> statement.append(idx[0]++ > 0 ? "," : "")
.append("`") .append("`")
.append(c.getInternalName()) .append(c.getAlias() != null ? c.getAlias() : c.getColumn().getInternalName())
.append("`")); .append("`"));
statement.append(" FROM `") statement.append(" FROM `")
.append(view.getInternalName()) .append(view.getInternalName())
......
...@@ -6,7 +6,7 @@ import at.tuwien.api.error.ApiErrorDto; ...@@ -6,7 +6,7 @@ import at.tuwien.api.error.ApiErrorDto;
import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.database.table.columns.TableColumn;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.mapper.TableMapper; import at.tuwien.mapper.TableMapper;
import at.tuwien.service.TableService; import at.tuwien.service.TableColumnService;
import at.tuwien.utils.PrincipalUtil; import at.tuwien.utils.PrincipalUtil;
import at.tuwien.utils.UserUtil; import at.tuwien.utils.UserUtil;
import at.tuwien.validation.EndpointValidator; import at.tuwien.validation.EndpointValidator;
...@@ -35,14 +35,15 @@ import java.security.Principal; ...@@ -35,14 +35,15 @@ import java.security.Principal;
public class TableColumnEndpoint { public class TableColumnEndpoint {
private final TableMapper tableMapper; private final TableMapper tableMapper;
private final TableService tableService;
private final EndpointValidator endpointValidator; private final EndpointValidator endpointValidator;
private final TableColumnService tableColumnService;
@Autowired @Autowired
public TableColumnEndpoint(TableMapper tableMapper, TableService tableService, EndpointValidator endpointValidator) { public TableColumnEndpoint(TableMapper tableMapper, EndpointValidator endpointValidator,
TableColumnService tableColumnService) {
this.tableMapper = tableMapper; this.tableMapper = tableMapper;
this.tableService = tableService;
this.endpointValidator = endpointValidator; this.endpointValidator = endpointValidator;
this.tableColumnService = tableColumnService;
} }
@PutMapping @PutMapping
...@@ -76,8 +77,7 @@ public class TableColumnEndpoint { ...@@ -76,8 +77,7 @@ public class TableColumnEndpoint {
@NotNull @PathVariable("tableId") Long tableId, @NotNull @PathVariable("tableId") Long tableId,
@NotNull @PathVariable("columnId") Long columnId, @NotNull @PathVariable("columnId") Long columnId,
@NotNull @Valid @RequestBody ColumnSemanticsUpdateDto updateDto, @NotNull @Valid @RequestBody ColumnSemanticsUpdateDto updateDto,
@NotNull Principal principal, @NotNull Principal principal)
@NotNull @RequestHeader("Authorization") String authorization)
throws TableNotFoundException, TableMalformedException, DatabaseNotFoundException, NotAllowedException, throws TableNotFoundException, TableMalformedException, DatabaseNotFoundException, NotAllowedException,
AccessDeniedException { AccessDeniedException {
log.debug("endpoint update table, id={}, tableId={}, columnId={}, {}", id, tableId, columnId, PrincipalUtil.formatForDebug(principal)); log.debug("endpoint update table, id={}, tableId={}, columnId={}, {}", id, tableId, columnId, PrincipalUtil.formatForDebug(principal));
...@@ -85,11 +85,12 @@ public class TableColumnEndpoint { ...@@ -85,11 +85,12 @@ public class TableColumnEndpoint {
endpointValidator.validateOnlyAccess(id, principal, true); endpointValidator.validateOnlyAccess(id, principal, true);
endpointValidator.validateOnlyOwnerOrWriteAll(id, tableId, principal); endpointValidator.validateOnlyOwnerOrWriteAll(id, tableId, principal);
} }
final TableColumn column = tableService.update(id, tableId, columnId, updateDto, authorization); final TableColumn column = tableColumnService.update(id, tableId, columnId, updateDto);
log.info("Updated table semantics of table with id {} and database with id {}", tableId, id); log.info("Updated table semantics of table with id {} and database with id {}", tableId, id);
final ColumnDto dto = tableMapper.tableColumnToColumnDto(column); final ColumnDto columnDto = tableMapper.tableColumnToColumnDto(column);
log.trace("find table data resulted in column {}", columnDto);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(dto); .body(columnDto);
} }
} }
...@@ -14,7 +14,6 @@ import at.tuwien.utils.PrincipalUtil; ...@@ -14,7 +14,6 @@ import at.tuwien.utils.PrincipalUtil;
import at.tuwien.utils.UserUtil; import at.tuwien.utils.UserUtil;
import at.tuwien.validation.EndpointValidator; import at.tuwien.validation.EndpointValidator;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.ExternalDocumentation;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
...@@ -174,6 +173,14 @@ public class TableDataEndpoint { ...@@ -174,6 +173,14 @@ public class TableDataEndpoint {
log.debug("endpoint insert data from csv, databaseId={}, tableId={}, data={}, {}", databaseId, tableId, data, PrincipalUtil.formatForDebug(principal)); log.debug("endpoint insert data from csv, databaseId={}, tableId={}, data={}, {}", databaseId, tableId, data, PrincipalUtil.formatForDebug(principal));
/* check */ /* check */
endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(databaseId, tableId, principal); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(databaseId, tableId, principal);
if (data.getNullElement() == null) {
log.debug("null element not present, default to empty string");
data.setNullElement("");
}
if (data.getLineTermination() == null) {
log.debug("line termination not present, default to \\r\\n");
data.setLineTermination("\r\n");
}
/* insert */ /* insert */
queryService.insert(databaseId, tableId, data, principal); queryService.insert(databaseId, tableId, data, principal);
return ResponseEntity.accepted() return ResponseEntity.accepted()
...@@ -229,6 +236,15 @@ public class TableDataEndpoint { ...@@ -229,6 +236,15 @@ public class TableDataEndpoint {
log.error("Failed to view table data: database with id {} is private and user has no authority", databaseId); log.error("Failed to view table data: database with id {} is private and user has no authority", databaseId);
throw new NotAllowedException("Failed to view table data: database with id " + databaseId + " is private and user has no authority"); throw new NotAllowedException("Failed to view table data: database with id " + databaseId + " is private and user has no authority");
} }
/* default */
if (page == null) {
log.trace("page is null: default to 0");
page = 0L;
}
if (size == null) {
log.trace("size is null: default to 10");
size = 10L;
}
/* find */ /* find */
final QueryResultDto response = queryService.tableFindAll(databaseId, tableId, timestamp, page, size, principal); final QueryResultDto response = queryService.tableFindAll(databaseId, tableId, timestamp, page, size, principal);
log.trace("find table data resulted in result {}", response); log.trace("find table data resulted in result {}", response);
......
...@@ -294,6 +294,15 @@ public class ViewEndpoint { ...@@ -294,6 +294,15 @@ public class ViewEndpoint {
throw new NotAllowedException("Failed to view data of private view: role missing"); throw new NotAllowedException("Failed to view data of private view: role missing");
} }
} }
/* default */
if (page == null) {
log.trace("page is null: default to 0");
page = 0L;
}
if (size == null) {
log.trace("size is null: default to 10");
size = 10L;
}
/* find */ /* find */
log.debug("find view data for database with id {}", databaseId); log.debug("find view data for database with id {}", databaseId);
final View view = viewService.findById(databaseId, viewId, principal); final View view = viewService.findById(databaseId, viewId, principal);
......
...@@ -40,7 +40,7 @@ spring: ...@@ -40,7 +40,7 @@ spring:
loadbalancer.ribbon.enabled: false loadbalancer.ribbon.enabled: false
management.endpoints.web.exposure.include: health,info,prometheus management.endpoints.web.exposure.include: health,info,prometheus
server: server:
port: 19099 port: 9099
logging: logging:
pattern.console: "%d %highlight(%-5level) %msg%n" pattern.console: "%d %highlight(%-5level) %msg%n"
level: level:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment