Skip to content
Snippets Groups Projects
Commit 8eadc95c authored by Moritz Staudinger's avatar Moritz Staudinger
Browse files

refactored execute to use re-execute, limited on resultnumber

Former-commit-id: 60fdf6dc
parent 607c8abe
No related branches found
No related tags found
No related merge requests found
...@@ -53,9 +53,9 @@ public class QueryEndpoint { ...@@ -53,9 +53,9 @@ public class QueryEndpoint {
public ResponseEntity<QueryResultDto> execute(@NotNull @PathVariable("id") Long id, public ResponseEntity<QueryResultDto> execute(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId, @NotNull @PathVariable("databaseId") Long databaseId,
@Valid @RequestBody ExecuteStatementDto data, @Valid @RequestBody ExecuteStatementDto data,
@RequestParam("page") Long page, @RequestParam("size") Long size) @RequestParam(value = "page", required = false ) Long page, @RequestParam(value = "size", required = false) Long size)
throws DatabaseNotFoundException, ImageNotSupportedException, QueryStoreException, QueryMalformedException, throws DatabaseNotFoundException, ImageNotSupportedException, QueryStoreException, QueryMalformedException,
TableNotFoundException, ContainerNotFoundException { TableNotFoundException, ContainerNotFoundException, SQLException, JSQLParserException {
/* validation */ /* validation */
if (data.getStatement() == null || data.getStatement().isBlank()) { if (data.getStatement() == null || data.getStatement().isBlank()) {
log.error("Query is empty"); log.error("Query is empty");
...@@ -103,7 +103,7 @@ public class QueryEndpoint { ...@@ -103,7 +103,7 @@ public class QueryEndpoint {
public ResponseEntity<QueryResultDto> reExecute(@NotNull @PathVariable("id") Long id, public ResponseEntity<QueryResultDto> reExecute(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId, @NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @PathVariable("queryId") Long queryId, @NotNull @PathVariable("queryId") Long queryId,
@RequestParam("page") Long page, @RequestParam("size") Long size) @RequestParam(value = "page", required = false) Long page, @RequestParam(value = "size", required = false) Long size)
throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
TableNotFoundException, QueryMalformedException, ContainerNotFoundException, SQLException, JSQLParserException { TableNotFoundException, QueryMalformedException, ContainerNotFoundException, SQLException, JSQLParserException {
final Query query = storeService.findOne(id, databaseId, queryId); final Query query = storeService.findOne(id, databaseId, queryId);
......
...@@ -10,6 +10,7 @@ import at.tuwien.exception.*; ...@@ -10,6 +10,7 @@ import at.tuwien.exception.*;
import at.tuwien.service.StoreService; import at.tuwien.service.StoreService;
import at.tuwien.service.impl.QueryServiceImpl; import at.tuwien.service.impl.QueryServiceImpl;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.sf.jsqlparser.JSQLParserException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -19,6 +20,7 @@ import org.springframework.http.HttpStatus; ...@@ -19,6 +20,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.sql.SQLException;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -45,7 +47,7 @@ public class QueryEndpointUnitTest extends BaseUnitTest { ...@@ -45,7 +47,7 @@ public class QueryEndpointUnitTest extends BaseUnitTest {
@Test @Test
public void execute_succeeds() throws TableNotFoundException, QueryStoreException, QueryMalformedException, public void execute_succeeds() throws TableNotFoundException, QueryStoreException, QueryMalformedException,
DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException { DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException, SQLException, JSQLParserException {
final ExecuteStatementDto request = ExecuteStatementDto.builder() final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_1_STATEMENT) .statement(QUERY_1_STATEMENT)
.build(); .build();
...@@ -71,7 +73,7 @@ public class QueryEndpointUnitTest extends BaseUnitTest { ...@@ -71,7 +73,7 @@ public class QueryEndpointUnitTest extends BaseUnitTest {
@Test @Test
public void execute_emptyResult_succeeds() throws TableNotFoundException, QueryStoreException, public void execute_emptyResult_succeeds() throws TableNotFoundException, QueryStoreException,
QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException { QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException, SQLException, JSQLParserException {
final ExecuteStatementDto request = ExecuteStatementDto.builder() final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_1_STATEMENT) .statement(QUERY_1_STATEMENT)
.build(); .build();
...@@ -97,7 +99,7 @@ public class QueryEndpointUnitTest extends BaseUnitTest { ...@@ -97,7 +99,7 @@ public class QueryEndpointUnitTest extends BaseUnitTest {
@Test @Test
public void execute_tableNotFound_fails() throws TableNotFoundException, QueryMalformedException, public void execute_tableNotFound_fails() throws TableNotFoundException, QueryMalformedException,
DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException, QueryStoreException { DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException, QueryStoreException, SQLException, JSQLParserException {
final ExecuteStatementDto request = ExecuteStatementDto.builder() final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_1_STATEMENT) .statement(QUERY_1_STATEMENT)
.build(); .build();
......
...@@ -17,6 +17,7 @@ import com.github.dockerjava.api.model.Bind; ...@@ -17,6 +17,7 @@ import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Network; import com.github.dockerjava.api.model.Network;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.sf.jsqlparser.JSQLParserException;
import org.junit.Rule; import org.junit.Rule;
import org.junit.rules.Timeout; import org.junit.rules.Timeout;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
...@@ -173,7 +174,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest { ...@@ -173,7 +174,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
@Test @Test
public void execute_succeeds() throws DatabaseNotFoundException, ImageNotSupportedException, InterruptedException, public void execute_succeeds() throws DatabaseNotFoundException, ImageNotSupportedException, InterruptedException,
QueryMalformedException, TableNotFoundException, QueryStoreException, ContainerNotFoundException { QueryMalformedException, TableNotFoundException, QueryStoreException, ContainerNotFoundException, SQLException, JSQLParserException {
final ExecuteStatementDto request = ExecuteStatementDto.builder() final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement(QUERY_1_STATEMENT) .statement(QUERY_1_STATEMENT)
.build(); .build();
...@@ -207,7 +208,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest { ...@@ -207,7 +208,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
@Disabled @Disabled
public void execute_modifyData_fails() throws DatabaseNotFoundException, ImageNotSupportedException, public void execute_modifyData_fails() throws DatabaseNotFoundException, ImageNotSupportedException,
InterruptedException, QueryMalformedException, TableNotFoundException, QueryStoreException, InterruptedException, QueryMalformedException, TableNotFoundException, QueryStoreException,
ContainerNotFoundException { ContainerNotFoundException, SQLException, JSQLParserException {
final ExecuteStatementDto request = ExecuteStatementDto.builder() final ExecuteStatementDto request = ExecuteStatementDto.builder()
.statement("DELETE FROM `weather_aus`;") .statement("DELETE FROM `weather_aus`;")
.build(); .build();
......
...@@ -32,7 +32,7 @@ public interface QueryService { ...@@ -32,7 +32,7 @@ public interface QueryService {
* @throws ImageNotSupportedException * @throws ImageNotSupportedException
*/ */
QueryResultDto execute(Long containerId, Long databaseId, ExecuteStatementDto query, Long page, Long size) throws TableNotFoundException, QueryResultDto execute(Long containerId, Long databaseId, ExecuteStatementDto query, Long page, Long size) throws TableNotFoundException,
QueryStoreException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException; QueryStoreException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException, SQLException, JSQLParserException;
/** /**
* Re-Executes an arbitrary query on the database container. We allow the user to only view the data, therefore the * Re-Executes an arbitrary query on the database container. We allow the user to only view the data, therefore the
......
...@@ -6,6 +6,7 @@ import at.tuwien.api.database.query.SaveStatementDto; ...@@ -6,6 +6,7 @@ import at.tuwien.api.database.query.SaveStatementDto;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.querystore.Query; import at.tuwien.querystore.Query;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
...@@ -69,4 +70,8 @@ public interface StoreService { ...@@ -69,4 +70,8 @@ public interface StoreService {
Instant execution) throws QueryStoreException, DatabaseNotFoundException, ImageNotSupportedException, Instant execution) throws QueryStoreException, DatabaseNotFoundException, ImageNotSupportedException,
ContainerNotFoundException; ContainerNotFoundException;
@Transactional(readOnly = true)
Query update(Long containerId, Long databaseId, QueryResultDto result, Long resultNumber, Query metadata)
throws QueryStoreException, DatabaseNotFoundException, ImageNotSupportedException,
ContainerNotFoundException;
} }
...@@ -61,42 +61,12 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService ...@@ -61,42 +61,12 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
@Override @Override
@Transactional @Transactional
public QueryResultDto execute(Long containerId, Long databaseId, ExecuteStatementDto statement, Long page, Long size) public QueryResultDto execute(Long containerId, Long databaseId, ExecuteStatementDto statement, Long page, Long size)
throws DatabaseNotFoundException, ImageNotSupportedException, QueryMalformedException, QueryStoreException, ContainerNotFoundException { throws DatabaseNotFoundException, ImageNotSupportedException, QueryMalformedException, QueryStoreException, ContainerNotFoundException, TableNotFoundException, SQLException, JSQLParserException {
/* find */
final Database database = databaseService.find(databaseId);
if (!database.getContainer().getImage().getRepository().equals("mariadb")) {
throw new ImageNotSupportedException("Currently only MariaDB is supported");
}
/* run query */
final long startSession = System.currentTimeMillis();
final SessionFactory factory = getSessionFactory(database);
final Session session = factory.openSession();
log.debug("opened hibernate session in {} ms", System.currentTimeMillis() - startSession);
session.beginTransaction();
/* prepare the statement */
Instant i = Instant.now(); Instant i = Instant.now();
final NativeQuery<?> query = session.createSQLQuery(queryMapper.queryToRawTimestampedQuery(statement.getStatement(), database, i)); Query q = storeService.insert(containerId, databaseId, null, statement, i);
final int affectedTuples; final QueryResultDto result = this.reExecute(containerId,databaseId,q,page,size);
try { Long resultNumber = 0L;
log.debug("execute raw view-only query {}", statement); q = storeService.update(containerId,databaseId,result, resultNumber,q);
affectedTuples = query.executeUpdate();
log.info("Execution on database id {} affected {} rows", databaseId, affectedTuples);
session.getTransaction()
.commit();
} catch (SQLGrammarException e) {
session.close();
factory.close();
throw new QueryMalformedException("Query not valid for this database", e);
}
/* map the result to the tables (with respective columns) from the statement metadata */
final List<TableColumn> columns = parseColumns(databaseId, statement);
final QueryResultDto result = queryMapper.resultListToQueryResultDto(columns, query.getResultList());
/* Save query in the querystore */
Query q = storeService.insert(containerId, databaseId, result, statement, i);
result.setId(q.getId());
session.close();
factory.close();
log.debug("query id {}", result.getId());
return result; return result;
} }
......
...@@ -146,4 +146,43 @@ public class StoreServiceImpl extends HibernateConnector implements StoreService ...@@ -146,4 +146,43 @@ public class StoreServiceImpl extends HibernateConnector implements StoreService
return query; return query;
} }
@Override
@Transactional(readOnly = true)
public Query update(Long containerId, Long databaseId, QueryResultDto result, Long resultNumber, Query metadata)
throws QueryStoreException, DatabaseNotFoundException, ImageNotSupportedException,
ContainerNotFoundException {
/* find */
final Container container = containerService.find(containerId);
final Database database = databaseService.find(databaseId);
if (!database.getContainer().getImage().getRepository().equals("mariadb")) {
throw new ImageNotSupportedException("Currently only MariaDB is supported");
}
log.debug("Update database id {}, metadata {}", databaseId, metadata);
/* save */
final SessionFactory factory = getSessionFactory(database, true);
final Session session = factory.openSession();
final Transaction transaction = session.beginTransaction();
final Query query = Query.builder()
.cid(containerId)
.dbid(databaseId)
.query(metadata.getQuery())
.queryNormalized(metadata.getQuery())
.queryHash(DigestUtils.sha256Hex(metadata.getQuery()))
.resultNumber(resultNumber)
.resultHash(storeMapper.queryResultDtoToString(result))
.execution(metadata.getExecution())
.build();
session.update(query);
transaction.commit();
/* store the result in the query store */
log.info("Update query with id {}", query.getId());
log.debug("saved query {}", query);
session.close();
factory.close();
return query;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment