diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java index 9d65ebf4ec9738d87e70a7955f0fa2b82d7285ec..867b1a10b05d25266fa40b5efe806177bb4ff56e 100644 --- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java +++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java @@ -95,27 +95,36 @@ public class TableDataEndpoint { @NotNull @PathVariable("tableId") Long tableId, @RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Long page, - @RequestParam(required = false) Long size) + @RequestParam(required = false) Long size, + @RequestParam(required = false) String sortBy, + @RequestParam(required = false) Boolean sortDesc) throws TableNotFoundException, DatabaseNotFoundException, DatabaseConnectionException, ImageNotSupportedException, TableMalformedException, PaginationException, ContainerNotFoundException, - QueryStoreException { + QueryStoreException, SortDataException { if ((page == null && size != null) || (page != null && size == null)) { log.error("Cannot perform pagination with only one of page/size set."); log.debug("invalid pagination specification, one of page/size is null, either both should be null or none."); throw new PaginationException("Invalid pagination parameters"); } if (page != null && page < 0) { - throw new PaginationException("Page number cannot be lower than 0"); + log.error("Failed to paginate: page number cannot be lower than 0"); + throw new PaginationException("Failed to paginate"); } if (size != null && size <= 0) { - throw new PaginationException("Page number cannot be lower or equal to 0"); + log.error("Failed to paginate: page number cannot be lower or equal to 0"); + throw new PaginationException("Failed to paginate"); + } + if ((sortBy != null && sortDesc == null) || (sortBy == null && sortDesc != null)) { + log.error("Failed to sort: both sortBy and sortDesc must be present or absent"); + throw new SortDataException("Failed to sort"); } /* fixme query store maybe not created, create it through running findAll() */ storeService.findAll(id, databaseId); final BigInteger count = queryService.count(id, databaseId, tableId, timestamp); final HttpHeaders headers = new HttpHeaders(); headers.set("FDA-COUNT", count.toString()); - final QueryResultDto response = queryService.findAll(id, databaseId, tableId, timestamp, page, size); + final QueryResultDto response = queryService.findAll(id, databaseId, tableId, timestamp, page, size, sortBy, + sortDesc); return ResponseEntity.ok() .headers(headers) .body(response); diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java index a6347e7c4716aa8c9de712b48bfe8dcfcfda844a..1b09864f60db0df211b6848c85350b0dfd5a305f 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java @@ -78,21 +78,22 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { @Test public void getAll_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException, - DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException, QueryStoreException { + DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException, + QueryStoreException, SortDataException { /* test */ - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null, null, null); } @Test public void findAll_noPagination_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException, DatabaseNotFoundException, ImageNotSupportedException, PaginationException, - ContainerNotFoundException, QueryStoreException { + ContainerNotFoundException, QueryStoreException, SortDataException { final Long page = null; final Long size = null; /* test */ - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); } @Test @@ -102,7 +103,7 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(PaginationException.class, () -> { - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); }); } @@ -113,7 +114,7 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(PaginationException.class, () -> { - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); }); } @@ -124,7 +125,7 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(PaginationException.class, () -> { - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); }); } @@ -135,7 +136,7 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(PaginationException.class, () -> { - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); }); } @@ -146,7 +147,7 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(PaginationException.class, () -> { - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); }); } @@ -157,7 +158,7 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(PaginationException.class, () -> { - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); }); } @@ -168,19 +169,19 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { /* test */ assertThrows(PaginationException.class, () -> { - dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size); + dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1_CREATED, page, size, null, null); }); } @Test public void getAllTotal_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException, DatabaseNotFoundException, ImageNotSupportedException, - PaginationException, ContainerNotFoundException, QueryStoreException { + PaginationException, ContainerNotFoundException, QueryStoreException, SortDataException { final Instant timestamp = Instant.now(); /* test */ final ResponseEntity<QueryResultDto> response = dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, - TABLE_1_ID, timestamp, null, null); + TABLE_1_ID, timestamp, null, null, null, null); assertNotNull(response); assertEquals(HttpStatus.OK, response.getStatusCode()); } @@ -188,12 +189,12 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { @Test public void getAllCount_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException, DatabaseNotFoundException, ImageNotSupportedException, - PaginationException, ContainerNotFoundException, QueryStoreException { + PaginationException, ContainerNotFoundException, QueryStoreException, SortDataException { final Instant timestamp = Instant.now(); /* test */ final ResponseEntity<QueryResultDto> response = dataEndpoint.getAll(CONTAINER_1_ID, DATABASE_1_ID, - TABLE_1_ID, timestamp, null, null); + TABLE_1_ID, timestamp, null, null, null, null); assertNotNull(response); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(response.getHeaders().containsKey("FDA-COUNT")); diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java index fa5cb52c411f7978867e0da1ba7bfd4cb4d62ca7..4a138f9a49d852caa582fd04dff9342be6402f21 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java @@ -152,7 +152,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest { /* test */ final QueryResultDto result = queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), - null, null); + null, null, null, null); assertEquals(3, result.getResult().size()); assertEquals(BigInteger.valueOf(1L), result.getResult().get(0).get(COLUMN_1_1_NAME)); assertEquals(toInstant("2008-12-01"), result.getResult().get(0).get(COLUMN_1_2_NAME)); diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java index bdd0cbaa2dac96c734bfe74fc00df646d1762ff0..aced7d3a3bebcaa86e4e7dceff0cdab7afb10c76 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceUnitTest.java @@ -138,7 +138,7 @@ public class QueryServiceUnitTest extends BaseUnitTest { .thenReturn(Optional.of(TABLE_1)); /* test */ - queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size); + queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, null, null); } @Test @@ -154,7 +154,7 @@ public class QueryServiceUnitTest extends BaseUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size); + queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, null, null); }); } @@ -171,7 +171,7 @@ public class QueryServiceUnitTest extends BaseUnitTest { /* test */ assertThrows(DatabaseNotFoundException.class, () -> { - queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size); + queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, null, null); }); } @@ -205,7 +205,7 @@ public class QueryServiceUnitTest extends BaseUnitTest { .thenReturn(Optional.of(TABLE_1)); /* test */ - queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null); + queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null, null, null); } @Test @@ -221,7 +221,7 @@ public class QueryServiceUnitTest extends BaseUnitTest { .thenReturn(Optional.of(TABLE_1)); /* test */ - queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null); + queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, null, null); } } diff --git a/fda-query-service/services/src/main/java/at/tuwien/exception/SortDataException.java b/fda-query-service/services/src/main/java/at/tuwien/exception/SortDataException.java new file mode 100644 index 0000000000000000000000000000000000000000..aef5cfa078a1babde81ad4c49de511a4059be1d9 --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/exception/SortDataException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class SortDataException extends Exception { + + public SortDataException(String msg) { + super(msg); + } + + public SortDataException(String msg, Throwable thr) { + super(msg, thr); + } + + public SortDataException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java index 805327430e1dcad63ce4c877126fcc1a9bfcbc3b..a75e5239225505f67bfe0a2d8156866d8b3763be 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java +++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java @@ -168,7 +168,8 @@ public interface QueryMapper { "';"; } - default String tableToRawFindAllQuery(Table table, Instant timestamp, Long size, Long page) + default String tableToRawFindAllQuery(Table table, Instant timestamp, Long size, Long page, String sortBy, + Boolean sortDesc) throws ImageNotSupportedException { /* param check */ if (!table.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) { @@ -192,6 +193,14 @@ public interface QueryMapper { .append("` FOR SYSTEM_TIME AS OF TIMESTAMP'") .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("Europe/Vienna"))) .append("'"); + if (sortBy != null && sortDesc != null) { + /* sorting requested */ + query.append(" ORDER BY ") + .append("`") + .append(sortBy) + .append("` ") + .append(sortDesc ? "DESC" : "ASC"); + } if (size != null && page != null) { log.trace("pagination size/limit of {}", size); query.append(" LIMIT ") diff --git a/fda-query-service/services/src/main/java/at/tuwien/querystore/Column.java b/fda-query-service/services/src/main/java/at/tuwien/querystore/Column.java deleted file mode 100644 index 8075f71848c3a70a6253e4c6d0f3d2bbc3f66548..0000000000000000000000000000000000000000 --- a/fda-query-service/services/src/main/java/at/tuwien/querystore/Column.java +++ /dev/null @@ -1,50 +0,0 @@ -package at.tuwien.querystore; - -import lombok.*; -import org.hibernate.annotations.GenericGenerator; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import java.io.Serializable; -import java.time.Instant; - -@Data -@Entity -@javax.persistence.Table(name = "qs_column") -@Builder -@AllArgsConstructor -@NoArgsConstructor -@ToString -@EntityListeners(AuditingEntityListener.class) -public class Column implements Serializable { - - @Id - @EqualsAndHashCode.Include - @GeneratedValue(generator = "column-sequence") - @GenericGenerator( - name = "column-sequence", - strategy = "enhanced-sequence", - parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "qs_column_seq") - ) - private Long id; - - @javax.persistence.Column(nullable = false) - private Long tid; - - @javax.persistence.Column(nullable = false) - private Long dbid; - - @javax.persistence.Column(nullable = false, updatable = false) - @CreatedDate - private Instant created; - - @javax.persistence.Column(name = "last_modified") - @LastModifiedDate - private Instant lastModified; - -} diff --git a/fda-query-service/services/src/main/java/at/tuwien/querystore/Query.java b/fda-query-service/services/src/main/java/at/tuwien/querystore/Query.java index 6798e5a2aaba6314417bb4add223e1a507a24bc1..b45aa30e71c54e19a027c8f8f72b40e9151abe4a 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/querystore/Query.java +++ b/fda-query-service/services/src/main/java/at/tuwien/querystore/Query.java @@ -62,9 +62,6 @@ public class Query implements Serializable { @CreatedDate private Instant created; - @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) - private List<Table> tables; - @javax.persistence.Column(name = "last_modified") @LastModifiedDate private Instant lastModified; diff --git a/fda-query-service/services/src/main/java/at/tuwien/querystore/Table.java b/fda-query-service/services/src/main/java/at/tuwien/querystore/Table.java deleted file mode 100644 index ee707cc8c115d087ad7f4914072640d8b28fa0b1..0000000000000000000000000000000000000000 --- a/fda-query-service/services/src/main/java/at/tuwien/querystore/Table.java +++ /dev/null @@ -1,48 +0,0 @@ -package at.tuwien.querystore; - -import lombok.*; -import org.hibernate.annotations.GenericGenerator; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import javax.persistence.*; -import java.io.Serializable; -import java.time.Instant; -import java.util.List; - -@Data -@Entity -@javax.persistence.Table(name = "qs_tables") -@Builder -@AllArgsConstructor -@NoArgsConstructor -@ToString -@EntityListeners(AuditingEntityListener.class) -public class Table implements Serializable { - - @Id - @EqualsAndHashCode.Include - @GeneratedValue(generator = "table-sequence") - @GenericGenerator( - name = "table-sequence", - strategy = "enhanced-sequence", - parameters = @org.hibernate.annotations.Parameter(name = "sequence_name", value = "qs_tables_seq") - ) - private Long id; - - @javax.persistence.Column(nullable = false) - private Long dbid; - - @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) - private List<Column> columns; - - @javax.persistence.Column(nullable = false, updatable = false) - @CreatedDate - private Instant created; - - @javax.persistence.Column(name = "last_modified") - @LastModifiedDate - private Instant lastModified; - -} diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java index 268ca3c68b6b0f77bb3019e2b90c4c212485418e..a18ad0ec5db4811391e5166df3e3c6221921a6b8 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java @@ -39,6 +39,8 @@ public interface QueryService { * @param timestamp The given time. * @param page The page. * @param size The page size. + * @param sortBy The column after which should be sorted. + * @param sortDesc The direction it should be sorted, if true the column is sorted Z to A, if false otherwise. * @return The select all data result * @throws ContainerNotFoundException The container was not found in the metadata database. * @throws TableNotFoundException The table was not found in the metadata database. @@ -48,7 +50,7 @@ public interface QueryService { * @throws DatabaseConnectionException The connection to the remote database was unsuccessful. */ QueryResultDto findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, - Long page, Long size) throws TableNotFoundException, DatabaseNotFoundException, + Long page, Long size, String sortBy, Boolean sortDesc) throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException, ContainerNotFoundException; diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java index 020f64168ab252c5fb807efb4568de0a9c61108a..84c252991a43514719c2b2fbc697c5796ccf4982 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java @@ -3,9 +3,7 @@ package at.tuwien.service.impl; import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; import at.tuwien.entities.database.Database; -import at.tuwien.querystore.Column; import at.tuwien.querystore.Query; -import at.tuwien.querystore.Table; import lombok.extern.log4j.Log4j2; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; @@ -60,9 +58,7 @@ public abstract class HibernateConnector { .setProperty("hibernate.c3p0.max_size", String.valueOf(MAX_SIZE)) .setProperty("hibernate.c3p0.acquire_increment", String.valueOf(INCREMENT_SIZE)) .setProperty("hibernate.c3p0.timeout", String.valueOf(TIMEOUT)) - .addAnnotatedClass(Query.class) - .addAnnotatedClass(Table.class) - .addAnnotatedClass(Column.class); + .addAnnotatedClass(Query.class); return configuration.buildSessionFactory(); } diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java index 756fcb33daf57dc2a43f826891381d563b9d9b7c..b15353fd0059c2f5ad5d209b2864a18a78927855 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java @@ -49,7 +49,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService } @Override - @Transactional + @Transactional(readOnly = true) public QueryResultDto execute(Long containerId, Long databaseId, ExecuteStatementDto statement) throws DatabaseNotFoundException, ImageNotSupportedException, QueryMalformedException { /* find */ @@ -87,11 +87,11 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService } @Override - @Transactional + @Transactional(readOnly = true) public QueryResultDto findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Long page, - Long size) throws TableNotFoundException, DatabaseNotFoundException, - ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException, - ContainerNotFoundException { + Long size, String sortBy, Boolean sortDesc) throws TableNotFoundException, + DatabaseNotFoundException, ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, + PaginationException, ContainerNotFoundException { /* find */ final Database database = databaseService.find(databaseId); final Table table = tableService.find(databaseId, tableId); @@ -102,7 +102,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService log.debug("opened hibernate session in {} ms", System.currentTimeMillis() - startSession); session.beginTransaction(); final NativeQuery<?> query = session.createSQLQuery(queryMapper.tableToRawFindAllQuery(table, timestamp, size, - page)); + page, sortBy, sortDesc)); final int affectedTuples; try { affectedTuples = query.executeUpdate(); @@ -128,7 +128,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService } @Override - @Transactional + @Transactional(readOnly = true) public BigInteger count(Long containerId, Long databaseId, Long tableId, Instant timestamp) throws DatabaseNotFoundException, TableNotFoundException, TableMalformedException, ImageNotSupportedException {