SQL: move requests' parameters to requests JSON body (#36149)
This commit is contained in:
parent
21d91f1268
commit
eead8a144b
|
@ -26,6 +26,7 @@ import java.util.Map;
|
|||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.columnInfo;
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.mode;
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.randomMode;
|
||||
|
||||
/**
|
||||
|
@ -111,10 +112,7 @@ public class RestSqlMultinodeIT extends ESRestTestCase {
|
|||
expected.put("rows", singletonList(singletonList(count)));
|
||||
|
||||
Request request = new Request("POST", "/_sql");
|
||||
if (false == mode.isEmpty()) {
|
||||
request.addParameter("mode", mode);
|
||||
}
|
||||
request.setJsonEntity("{\"query\": \"SELECT COUNT(*) FROM test\"}");
|
||||
request.setJsonEntity("{\"query\": \"SELECT COUNT(*) FROM test\"" + mode(mode) + "}");
|
||||
Map<String, Object> actual = responseToMap(client.performRequest(request));
|
||||
|
||||
if (false == expected.equals(actual)) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.Map;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.columnInfo;
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.mode;
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.randomMode;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
|
@ -66,10 +67,12 @@ public class RestSqlSecurityIT extends SqlSecurityTestCase {
|
|||
@Override
|
||||
public void expectScrollMatchesAdmin(String adminSql, String user, String userSql) throws Exception {
|
||||
String mode = randomMode();
|
||||
Map<String, Object> adminResponse = runSql(null, mode,
|
||||
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1}", ContentType.APPLICATION_JSON));
|
||||
Map<String, Object> otherResponse = runSql(user, mode,
|
||||
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1}", ContentType.APPLICATION_JSON));
|
||||
Map<String, Object> adminResponse = runSql(null,
|
||||
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1" + mode(mode) + "}",
|
||||
ContentType.APPLICATION_JSON));
|
||||
Map<String, Object> otherResponse = runSql(user,
|
||||
new StringEntity("{\"query\": \"" + adminSql + "\", \"fetch_size\": 1" + mode(mode) + "}",
|
||||
ContentType.APPLICATION_JSON));
|
||||
|
||||
String adminCursor = (String) adminResponse.remove("cursor");
|
||||
String otherCursor = (String) otherResponse.remove("cursor");
|
||||
|
@ -77,10 +80,10 @@ public class RestSqlSecurityIT extends SqlSecurityTestCase {
|
|||
assertNotNull(otherCursor);
|
||||
assertResponse(adminResponse, otherResponse);
|
||||
while (true) {
|
||||
adminResponse = runSql(null, mode,
|
||||
new StringEntity("{\"cursor\": \"" + adminCursor + "\"}", ContentType.APPLICATION_JSON));
|
||||
otherResponse = runSql(user, mode,
|
||||
new StringEntity("{\"cursor\": \"" + otherCursor + "\"}", ContentType.APPLICATION_JSON));
|
||||
adminResponse = runSql(null,
|
||||
new StringEntity("{\"cursor\": \"" + adminCursor + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON));
|
||||
otherResponse = runSql(user,
|
||||
new StringEntity("{\"cursor\": \"" + otherCursor + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON));
|
||||
adminCursor = (String) adminResponse.remove("cursor");
|
||||
otherCursor = (String) otherResponse.remove("cursor");
|
||||
assertResponse(adminResponse, otherResponse);
|
||||
|
@ -173,14 +176,11 @@ public class RestSqlSecurityIT extends SqlSecurityTestCase {
|
|||
}
|
||||
|
||||
private static Map<String, Object> runSql(@Nullable String asUser, String mode, String sql) throws IOException {
|
||||
return runSql(asUser, mode, new StringEntity("{\"query\": \"" + sql + "\"}", ContentType.APPLICATION_JSON));
|
||||
return runSql(asUser, new StringEntity("{\"query\": \"" + sql + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
private static Map<String, Object> runSql(@Nullable String asUser, String mode, HttpEntity entity) throws IOException {
|
||||
private static Map<String, Object> runSql(@Nullable String asUser, HttpEntity entity) throws IOException {
|
||||
Request request = new Request("POST", "/_sql");
|
||||
if (false == mode.isEmpty()) {
|
||||
request.addParameter("mode", mode);
|
||||
}
|
||||
if (asUser != null) {
|
||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
||||
options.addHeader("es-security-runas-user", asUser);
|
||||
|
@ -223,14 +223,15 @@ public class RestSqlSecurityIT extends SqlSecurityTestCase {
|
|||
public void testHijackScrollFails() throws Exception {
|
||||
createUser("full_access", "rest_minimal");
|
||||
|
||||
Map<String, Object> adminResponse = RestActions.runSql(null, randomMode(),
|
||||
new StringEntity("{\"query\": \"SELECT * FROM test\", \"fetch_size\": 1}", ContentType.APPLICATION_JSON));
|
||||
Map<String, Object> adminResponse = RestActions.runSql(null,
|
||||
new StringEntity("{\"query\": \"SELECT * FROM test\", \"fetch_size\": 1" + mode(randomMode()) + "}",
|
||||
ContentType.APPLICATION_JSON));
|
||||
|
||||
String cursor = (String) adminResponse.remove("cursor");
|
||||
assertNotNull(cursor);
|
||||
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> RestActions.runSql("full_access", randomMode(),
|
||||
new StringEntity("{\"cursor\":\"" + cursor + "\"}", ContentType.APPLICATION_JSON)));
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> RestActions.runSql("full_access",
|
||||
new StringEntity("{\"cursor\":\"" + cursor + "\"" + mode(randomMode()) + "}", ContentType.APPLICATION_JSON)));
|
||||
// TODO return a better error message for bad scrolls
|
||||
assertThat(e.getMessage(), containsString("No search context found for id"));
|
||||
assertEquals(404, e.getResponse().getStatusLine().getStatusCode());
|
||||
|
|
|
@ -35,6 +35,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.columnInfo;
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.mode;
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.randomMode;
|
||||
|
||||
public class UserFunctionIT extends ESRestTestCase {
|
||||
|
||||
|
@ -172,14 +174,11 @@ public class UserFunctionIT extends ESRestTestCase {
|
|||
}
|
||||
|
||||
private Map<String, Object> runSql(String asUser, String mode, String sql) throws IOException {
|
||||
return runSql(asUser, mode, new StringEntity("{\"query\": \"" + sql + "\"}", ContentType.APPLICATION_JSON));
|
||||
return runSql(asUser, new StringEntity("{\"query\": \"" + sql + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
private Map<String, Object> runSql(String asUser, String mode, HttpEntity entity) throws IOException {
|
||||
private Map<String, Object> runSql(String asUser, HttpEntity entity) throws IOException {
|
||||
Request request = new Request("POST", "/_sql");
|
||||
if (false == mode.isEmpty()) {
|
||||
request.addParameter("mode", mode);
|
||||
}
|
||||
if (asUser != null) {
|
||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
||||
options.addHeader("es-security-runas-user", asUser);
|
||||
|
@ -203,10 +202,6 @@ public class UserFunctionIT extends ESRestTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
private String randomMode() {
|
||||
return randomFrom("plain", "jdbc", "");
|
||||
}
|
||||
|
||||
private void index(String... docs) throws IOException {
|
||||
Request request = new Request("POST", "/test/test/_bulk");
|
||||
request.addParameter("refresh", "true");
|
||||
|
|
|
@ -15,12 +15,14 @@ import org.elasticsearch.client.RequestOptions;
|
|||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.common.CheckedSupplier;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.test.NotEqualMessageBuilder;
|
||||
import org.elasticsearch.test.rest.ESRestTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.StringUtils;
|
||||
import org.elasticsearch.xpack.sql.qa.ErrorsTestCase;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
|
@ -97,10 +99,10 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
for (int i = 0; i < 20; i += 2) {
|
||||
Map<String, Object> response;
|
||||
if (i == 0) {
|
||||
response = runSql(mode, new StringEntity(sqlRequest, ContentType.APPLICATION_JSON));
|
||||
response = runSql(new StringEntity(sqlRequest, ContentType.APPLICATION_JSON), "");
|
||||
} else {
|
||||
response = runSql(mode, new StringEntity("{\"cursor\":\"" + cursor + "\"}",
|
||||
ContentType.APPLICATION_JSON));
|
||||
response = runSql(new StringEntity("{\"cursor\":\"" + cursor + "\"" + mode(mode) + "}",
|
||||
ContentType.APPLICATION_JSON), StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
Map<String, Object> expected = new HashMap<>();
|
||||
|
@ -120,8 +122,8 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
}
|
||||
Map<String, Object> expected = new HashMap<>();
|
||||
expected.put("rows", emptyList());
|
||||
assertResponse(expected, runSql(mode, new StringEntity("{ \"cursor\":\"" + cursor + "\"}",
|
||||
ContentType.APPLICATION_JSON)));
|
||||
assertResponse(expected, runSql(new StringEntity("{ \"cursor\":\"" + cursor + "\"" + mode(mode) + "}",
|
||||
ContentType.APPLICATION_JSON), StringUtils.EMPTY));
|
||||
}
|
||||
|
||||
@AwaitsFix(bugUrl = "Unclear status, https://github.com/elastic/x-pack-elasticsearch/issues/2074")
|
||||
|
@ -136,8 +138,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
expected.put("size", 2);
|
||||
|
||||
// Default TimeZone is UTC
|
||||
assertResponse(expected, runSql(mode, new StringEntity("{\"query\":\"SELECT DAY_OF_YEAR(test), COUNT(*) FROM test\"}",
|
||||
ContentType.APPLICATION_JSON)));
|
||||
assertResponse(expected, runSql(mode, "SELECT DAY_OF_YEAR(test), COUNT(*) FROM test"));
|
||||
}
|
||||
|
||||
public void testScoreWithFieldNamedScore() throws IOException {
|
||||
|
@ -302,18 +303,14 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
}
|
||||
|
||||
private Map<String, Object> runSql(String mode, String sql) throws IOException {
|
||||
return runSql(mode, sql, "");
|
||||
return runSql(mode, sql, StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
private Map<String, Object> runSql(String mode, String sql, String suffix) throws IOException {
|
||||
return runSql(mode, new StringEntity("{\"query\":\"" + sql + "\"}", ContentType.APPLICATION_JSON), suffix);
|
||||
return runSql(new StringEntity("{\"query\":\"" + sql + "\"" + mode(mode) + "}", ContentType.APPLICATION_JSON), suffix);
|
||||
}
|
||||
|
||||
private Map<String, Object> runSql(String mode, HttpEntity sql) throws IOException {
|
||||
return runSql(mode, sql, "");
|
||||
}
|
||||
|
||||
private Map<String, Object> runSql(String mode, HttpEntity sql, String suffix) throws IOException {
|
||||
private Map<String, Object> runSql(HttpEntity sql, String suffix) throws IOException {
|
||||
Request request = new Request("POST", "/_sql" + suffix);
|
||||
request.addParameter("error_trace", "true"); // Helps with debugging in case something crazy happens on the server.
|
||||
request.addParameter("pretty", "true"); // Improves error reporting readability
|
||||
|
@ -321,9 +318,6 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
// We default to JSON but we force it randomly for extra coverage
|
||||
request.addParameter("format", "json");
|
||||
}
|
||||
if (false == mode.isEmpty()) {
|
||||
request.addParameter("mode", mode); // JDBC or PLAIN mode
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
// JSON is the default but randomly set it sometime for extra coverage
|
||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
||||
|
@ -331,6 +325,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
request.setOptions(options);
|
||||
}
|
||||
request.setEntity(sql);
|
||||
|
||||
Response response = client().performRequest(request);
|
||||
try (InputStream content = response.getEntity().getContent()) {
|
||||
return XContentHelper.convertToMap(JsonXContent.jsonXContent, content, false);
|
||||
|
@ -357,9 +352,9 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
Map<String, Object> expected = new HashMap<>();
|
||||
expected.put("columns", singletonList(columnInfo(mode, "test", "text", JDBCType.VARCHAR, 0)));
|
||||
expected.put("rows", singletonList(singletonList("foo")));
|
||||
assertResponse(expected, runSql(mode, new StringEntity("{\"query\":\"SELECT * FROM test\", " +
|
||||
"\"filter\":{\"match\": {\"test\": \"foo\"}}}",
|
||||
ContentType.APPLICATION_JSON)));
|
||||
assertResponse(expected, runSql(new StringEntity("{\"query\":\"SELECT * FROM test\", " +
|
||||
"\"filter\":{\"match\": {\"test\": \"foo\"}}" + mode(mode) + "}",
|
||||
ContentType.APPLICATION_JSON), StringUtils.EMPTY));
|
||||
}
|
||||
|
||||
public void testBasicQueryWithParameters() throws IOException {
|
||||
|
@ -373,16 +368,16 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
columnInfo(mode, "param", "integer", JDBCType.INTEGER, 11)
|
||||
));
|
||||
expected.put("rows", singletonList(Arrays.asList("foo", 10)));
|
||||
assertResponse(expected, runSql(mode, new StringEntity("{\"query\":\"SELECT test, ? param FROM test WHERE test = ?\", " +
|
||||
"\"params\":[{\"type\": \"integer\", \"value\": 10}, {\"type\": \"keyword\", \"value\": \"foo\"}]}",
|
||||
ContentType.APPLICATION_JSON)));
|
||||
assertResponse(expected, runSql(new StringEntity("{\"query\":\"SELECT test, ? param FROM test WHERE test = ?\", " +
|
||||
"\"params\":[{\"type\": \"integer\", \"value\": 10}, {\"type\": \"keyword\", \"value\": \"foo\"}]"
|
||||
+ mode(mode) + "}", ContentType.APPLICATION_JSON), StringUtils.EMPTY));
|
||||
}
|
||||
|
||||
public void testBasicTranslateQueryWithFilter() throws IOException {
|
||||
index("{\"test\":\"foo\"}",
|
||||
"{\"test\":\"bar\"}");
|
||||
|
||||
Map<String, Object> response = runSql("",
|
||||
Map<String, Object> response = runSql(
|
||||
new StringEntity("{\"query\":\"SELECT * FROM test\", \"filter\":{\"match\": {\"test\": \"foo\"}}}",
|
||||
ContentType.APPLICATION_JSON), "/translate/"
|
||||
);
|
||||
|
@ -424,7 +419,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
index("{\"salary\":100}",
|
||||
"{\"age\":20}");
|
||||
|
||||
Map<String, Object> response = runSql("",
|
||||
Map<String, Object> response = runSql(
|
||||
new StringEntity("{\"query\":\"SELECT avg(salary) FROM test GROUP BY abs(age) HAVING avg(salary) > 50 LIMIT 10\"}",
|
||||
ContentType.APPLICATION_JSON), "/translate/"
|
||||
);
|
||||
|
@ -551,10 +546,10 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
for (int i = 0; i < 20; i += 2) {
|
||||
Tuple<String, String> response;
|
||||
if (i == 0) {
|
||||
response = runSqlAsText("", new StringEntity(request, ContentType.APPLICATION_JSON), "text/plain");
|
||||
response = runSqlAsText(StringUtils.EMPTY, new StringEntity(request, ContentType.APPLICATION_JSON), "text/plain");
|
||||
} else {
|
||||
response = runSqlAsText("", new StringEntity("{\"cursor\":\"" + cursor + "\"}", ContentType.APPLICATION_JSON),
|
||||
"text/plain");
|
||||
response = runSqlAsText(StringUtils.EMPTY, new StringEntity("{\"cursor\":\"" + cursor + "\"}",
|
||||
ContentType.APPLICATION_JSON), "text/plain");
|
||||
}
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
|
@ -570,9 +565,10 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
}
|
||||
Map<String, Object> expected = new HashMap<>();
|
||||
expected.put("rows", emptyList());
|
||||
assertResponse(expected, runSql("", new StringEntity("{\"cursor\":\"" + cursor + "\"}", ContentType.APPLICATION_JSON)));
|
||||
assertResponse(expected, runSql(new StringEntity("{\"cursor\":\"" + cursor + "\"}", ContentType.APPLICATION_JSON),
|
||||
StringUtils.EMPTY));
|
||||
|
||||
Map<String, Object> response = runSql("", new StringEntity("{\"cursor\":\"" + cursor + "\"}", ContentType.APPLICATION_JSON),
|
||||
Map<String, Object> response = runSql(new StringEntity("{\"cursor\":\"" + cursor + "\"}", ContentType.APPLICATION_JSON),
|
||||
"/close");
|
||||
assertEquals(true, response.get("succeeded"));
|
||||
|
||||
|
@ -638,7 +634,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
}
|
||||
|
||||
private Tuple<String, String> runSqlAsText(String sql, String accept) throws IOException {
|
||||
return runSqlAsText("", new StringEntity("{\"query\":\"" + sql + "\"}", ContentType.APPLICATION_JSON), accept);
|
||||
return runSqlAsText(StringUtils.EMPTY, new StringEntity("{\"query\":\"" + sql + "\"}", ContentType.APPLICATION_JSON), accept);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -716,7 +712,11 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
|||
}
|
||||
|
||||
public static String randomMode() {
|
||||
return randomFrom("", "jdbc", "plain");
|
||||
return randomFrom(StringUtils.EMPTY, "jdbc", "plain");
|
||||
}
|
||||
|
||||
public static String mode(String mode) {
|
||||
return Strings.isEmpty(mode) ? StringUtils.EMPTY : ",\"mode\":\"" + mode + "\"";
|
||||
}
|
||||
|
||||
private void index(String... docs) throws IOException {
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.common.xcontent.XContentHelper;
|
|||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.test.rest.ESRestTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.StringUtils;
|
||||
import org.elasticsearch.xpack.sql.qa.FeatureMetric;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -25,6 +26,8 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.qa.rest.RestSqlTestCase.mode;
|
||||
|
||||
public abstract class RestSqlUsageTestCase extends ESRestTestCase {
|
||||
private List<IndexDocument> testData = Arrays.asList(
|
||||
new IndexDocument("used", "Don Quixote", 1072),
|
||||
|
@ -64,11 +67,11 @@ public abstract class RestSqlUsageTestCase extends ESRestTestCase {
|
|||
Map<String, Object> baseStats = getStats();
|
||||
List<Map<String, Map<String, Map>>> nodesListStats = (List) baseStats.get("stats");
|
||||
|
||||
// used for "client.id" request parameter value, but also for getting the stats from ES
|
||||
// used for "client_id" request parameter value, but also for getting the stats from ES
|
||||
clientType = randomFrom(ClientType.values()).toString();
|
||||
ignoreClientType = randomBoolean();
|
||||
|
||||
// "client.id" parameter will not be sent in the requests
|
||||
// "client_id" parameter will not be sent in the requests
|
||||
// and "clientType" will only be used for getting the stats back from ES
|
||||
if (ignoreClientType) {
|
||||
clientType = ClientType.REST.toString();
|
||||
|
@ -274,20 +277,15 @@ public abstract class RestSqlUsageTestCase extends ESRestTestCase {
|
|||
// We default to JSON but we force it randomly for extra coverage
|
||||
request.addParameter("format", "json");
|
||||
}
|
||||
if (false == mode.isEmpty()) {
|
||||
request.addParameter("mode", mode); // JDBC or PLAIN mode
|
||||
}
|
||||
// randomly use the "client.id" parameter or not
|
||||
if (false == ignoreClientType) {
|
||||
request.addParameter("client.id", restClient);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
// JSON is the default but randomly set it sometime for extra coverage
|
||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
||||
options.addHeader("Accept", randomFrom("*/*", "application/json"));
|
||||
request.setOptions(options);
|
||||
}
|
||||
request.setEntity(new StringEntity("{\"query\":\"" + sql + "\"}", ContentType.APPLICATION_JSON));
|
||||
request.setEntity(new StringEntity("{\"query\":\"" + sql + "\"" + mode(mode) +
|
||||
(ignoreClientType ? StringUtils.EMPTY : ",\"client_id\":\"" + restClient + "\"") + "}",
|
||||
ContentType.APPLICATION_JSON));
|
||||
client().performRequest(request);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
|||
import org.elasticsearch.common.xcontent.ToXContentFragment;
|
||||
import org.elasticsearch.index.query.AbstractQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
import org.elasticsearch.xpack.sql.proto.RequestInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
@ -39,6 +40,17 @@ public abstract class AbstractSqlQueryRequest extends AbstractSqlRequest impleme
|
|||
@Nullable
|
||||
private QueryBuilder filter = null;
|
||||
private List<SqlTypedParamValue> params = Collections.emptyList();
|
||||
|
||||
static final ParseField QUERY = new ParseField("query");
|
||||
static final ParseField CURSOR = new ParseField("cursor");
|
||||
static final ParseField PARAMS = new ParseField("params");
|
||||
static final ParseField TIME_ZONE = new ParseField("time_zone");
|
||||
static final ParseField FETCH_SIZE = new ParseField("fetch_size");
|
||||
static final ParseField REQUEST_TIMEOUT = new ParseField("request_timeout");
|
||||
static final ParseField PAGE_TIMEOUT = new ParseField("page_timeout");
|
||||
static final ParseField FILTER = new ParseField("filter");
|
||||
static final ParseField MODE = new ParseField("mode");
|
||||
static final ParseField CLIENT_ID = new ParseField("client_id");
|
||||
|
||||
public AbstractSqlQueryRequest() {
|
||||
super();
|
||||
|
@ -57,19 +69,22 @@ public abstract class AbstractSqlQueryRequest extends AbstractSqlRequest impleme
|
|||
}
|
||||
|
||||
protected static <R extends AbstractSqlQueryRequest> ObjectParser<R, Void> objectParser(Supplier<R> supplier) {
|
||||
// TODO: convert this into ConstructingObjectParser
|
||||
ObjectParser<R, Void> parser = new ObjectParser<>("sql/query", true, supplier);
|
||||
parser.declareString(AbstractSqlQueryRequest::query, new ParseField("query"));
|
||||
parser.declareObjectArray(AbstractSqlQueryRequest::params, (p, c) -> SqlTypedParamValue.fromXContent(p), new ParseField("params"));
|
||||
parser.declareString((request, zoneId) -> request.timeZone(TimeZone.getTimeZone(zoneId)), new ParseField("time_zone"));
|
||||
parser.declareInt(AbstractSqlQueryRequest::fetchSize, new ParseField("fetch_size"));
|
||||
// Using an ObjectParser here (vs. ConstructingObjectParser) because the latter needs to instantiate a concrete class
|
||||
// and we would duplicate the code from this class to its subclasses
|
||||
ObjectParser<R, Void> parser = new ObjectParser<>("sql/query", false, supplier);
|
||||
parser.declareString(AbstractSqlQueryRequest::query, QUERY);
|
||||
parser.declareString((request, mode) -> request.mode(Mode.fromString(mode)), MODE);
|
||||
parser.declareString((request, clientId) -> request.clientId(clientId), CLIENT_ID);
|
||||
parser.declareObjectArray(AbstractSqlQueryRequest::params, (p, c) -> SqlTypedParamValue.fromXContent(p), PARAMS);
|
||||
parser.declareString((request, zoneId) -> request.timeZone(TimeZone.getTimeZone(zoneId)), TIME_ZONE);
|
||||
parser.declareInt(AbstractSqlQueryRequest::fetchSize, FETCH_SIZE);
|
||||
parser.declareString((request, timeout) -> request.requestTimeout(TimeValue.parseTimeValue(timeout, Protocol.REQUEST_TIMEOUT,
|
||||
"request_timeout")), new ParseField("request_timeout"));
|
||||
"request_timeout")), REQUEST_TIMEOUT);
|
||||
parser.declareString(
|
||||
(request, timeout) -> request.pageTimeout(TimeValue.parseTimeValue(timeout, Protocol.PAGE_TIMEOUT, "page_timeout")),
|
||||
new ParseField("page_timeout"));
|
||||
PAGE_TIMEOUT);
|
||||
parser.declareObject(AbstractSqlQueryRequest::filter,
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), new ParseField("filter"));
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), FILTER);
|
||||
return parser;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ public abstract class AbstractSqlRequest extends ActionRequest implements ToXCon
|
|||
private RequestInfo requestInfo;
|
||||
|
||||
protected AbstractSqlRequest() {
|
||||
|
||||
this.requestInfo = new RequestInfo(Mode.PLAIN);
|
||||
}
|
||||
|
||||
protected AbstractSqlRequest(RequestInfo requestInfo) {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package org.elasticsearch.xpack.sql.action;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
|
@ -20,30 +19,37 @@ import java.util.Objects;
|
|||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.xpack.sql.action.AbstractSqlQueryRequest.CURSOR;
|
||||
import static org.elasticsearch.xpack.sql.action.AbstractSqlQueryRequest.MODE;
|
||||
import static org.elasticsearch.xpack.sql.action.AbstractSqlQueryRequest.CLIENT_ID;
|
||||
|
||||
/**
|
||||
* Request to clean all SQL resources associated with the cursor
|
||||
*/
|
||||
public class SqlClearCursorRequest extends AbstractSqlRequest {
|
||||
|
||||
private static final ConstructingObjectParser<SqlClearCursorRequest, Mode> PARSER =
|
||||
new ConstructingObjectParser<>(SqlClearCursorAction.NAME, true, (objects, mode) -> new SqlClearCursorRequest(
|
||||
mode,
|
||||
(String) objects[0]
|
||||
));
|
||||
private static final ConstructingObjectParser<SqlClearCursorRequest, RequestInfo> PARSER =
|
||||
// here the position in "objects" is the same as the fields parser declarations below
|
||||
new ConstructingObjectParser<>(SqlClearCursorAction.NAME, objects -> {
|
||||
RequestInfo requestInfo = new RequestInfo(Mode.fromString((String) objects[1]),
|
||||
(String) objects[2]);
|
||||
return new SqlClearCursorRequest(requestInfo, (String) objects[0]);
|
||||
});
|
||||
|
||||
static {
|
||||
PARSER.declareString(constructorArg(), new ParseField("cursor"));
|
||||
// "cursor" is required constructor parameter
|
||||
PARSER.declareString(constructorArg(), CURSOR);
|
||||
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), MODE);
|
||||
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), CLIENT_ID);
|
||||
}
|
||||
|
||||
private String cursor;
|
||||
|
||||
public SqlClearCursorRequest() {
|
||||
|
||||
}
|
||||
|
||||
public SqlClearCursorRequest(Mode mode, String cursor) {
|
||||
super(new RequestInfo(mode));
|
||||
public SqlClearCursorRequest(RequestInfo requestInfo, String cursor) {
|
||||
super(requestInfo);
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
|
@ -101,7 +107,7 @@ public class SqlClearCursorRequest extends AbstractSqlRequest {
|
|||
return new org.elasticsearch.xpack.sql.proto.SqlClearCursorRequest(cursor, requestInfo()).toXContent(builder, params);
|
||||
}
|
||||
|
||||
public static SqlClearCursorRequest fromXContent(XContentParser parser, Mode mode) {
|
||||
return PARSER.apply(parser, mode);
|
||||
public static SqlClearCursorRequest fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package org.elasticsearch.xpack.sql.action;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
@ -14,7 +13,6 @@ import org.elasticsearch.common.unit.TimeValue;
|
|||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.AbstractQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.xpack.sql.proto.RequestInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
@ -32,18 +30,14 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
|
|||
public class SqlQueryRequest extends AbstractSqlQueryRequest {
|
||||
private static final ObjectParser<SqlQueryRequest, Void> PARSER = objectParser(SqlQueryRequest::new);
|
||||
|
||||
public static final ParseField CURSOR = new ParseField("cursor");
|
||||
public static final ParseField FILTER = new ParseField("filter");
|
||||
|
||||
static {
|
||||
PARSER.declareString(SqlQueryRequest::cursor, CURSOR);
|
||||
PARSER.declareObject(SqlQueryRequest::filter,
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), FILTER);
|
||||
}
|
||||
|
||||
private String cursor = "";
|
||||
|
||||
public SqlQueryRequest() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SqlQueryRequest(String query, List<SqlTypedParamValue> params, QueryBuilder filter, TimeZone timeZone,
|
||||
|
@ -114,9 +108,7 @@ public class SqlQueryRequest extends AbstractSqlQueryRequest {
|
|||
pageTimeout(), filter(), cursor(), requestInfo()).toXContent(builder, params);
|
||||
}
|
||||
|
||||
public static SqlQueryRequest fromXContent(XContentParser parser, RequestInfo requestInfo) {
|
||||
SqlQueryRequest request = PARSER.apply(parser, null);
|
||||
request.requestInfo(requestInfo);
|
||||
return request;
|
||||
public static SqlQueryRequest fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import java.util.Objects;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static org.elasticsearch.xpack.sql.action.AbstractSqlQueryRequest.CURSOR;
|
||||
|
||||
/**
|
||||
* Response to perform an sql query
|
||||
|
@ -31,6 +32,7 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
|
||||
// TODO: Simplify cursor handling
|
||||
private String cursor;
|
||||
private Mode mode;
|
||||
private List<ColumnInfo> columns;
|
||||
// TODO investigate reusing Page here - it probably is much more efficient
|
||||
private List<List<Object>> rows;
|
||||
|
@ -38,8 +40,9 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
public SqlQueryResponse() {
|
||||
}
|
||||
|
||||
public SqlQueryResponse(String cursor, @Nullable List<ColumnInfo> columns, List<List<Object>> rows) {
|
||||
public SqlQueryResponse(String cursor, Mode mode, @Nullable List<ColumnInfo> columns, List<List<Object>> rows) {
|
||||
this.cursor = cursor;
|
||||
this.mode = mode;
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
@ -134,7 +137,6 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
Mode mode = Mode.fromString(params.param("mode"));
|
||||
builder.startObject();
|
||||
{
|
||||
if (columns != null) {
|
||||
|
@ -157,7 +159,7 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
builder.endArray();
|
||||
|
||||
if (cursor.equals("") == false) {
|
||||
builder.field(SqlQueryRequest.CURSOR.getPreferredName(), cursor);
|
||||
builder.field(CURSOR.getPreferredName(), cursor);
|
||||
}
|
||||
}
|
||||
return builder.endObject();
|
||||
|
|
|
@ -13,9 +13,8 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.RequestInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -31,6 +30,7 @@ public class SqlTranslateRequest extends AbstractSqlQueryRequest {
|
|||
private static final ObjectParser<SqlTranslateRequest, Void> PARSER = objectParser(SqlTranslateRequest::new);
|
||||
|
||||
public SqlTranslateRequest() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SqlTranslateRequest(String query, List<SqlTypedParamValue> params, QueryBuilder filter, TimeZone timeZone,
|
||||
|
@ -56,9 +56,8 @@ public class SqlTranslateRequest extends AbstractSqlQueryRequest {
|
|||
return "SQL Translate [" + query() + "][" + filter() + "]";
|
||||
}
|
||||
|
||||
public static SqlTranslateRequest fromXContent(XContentParser parser, Mode mode) {
|
||||
public static SqlTranslateRequest fromXContent(XContentParser parser) {
|
||||
SqlTranslateRequest request = PARSER.apply(parser, null);
|
||||
request.requestInfo(new RequestInfo(mode));
|
||||
return request;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,22 +9,27 @@ import org.elasticsearch.common.io.stream.Writeable;
|
|||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.AbstractSerializingTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.RequestInfo;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.proto.RequestInfo.CLIENT_IDS;
|
||||
|
||||
public class SqlClearCursorRequestTests extends AbstractSerializingTestCase<SqlClearCursorRequest> {
|
||||
public Mode testMode;
|
||||
|
||||
public RequestInfo requestInfo;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
testMode = randomFrom(Mode.values());
|
||||
requestInfo = new RequestInfo(randomFrom(Mode.values()),
|
||||
randomFrom(randomFrom(CLIENT_IDS), randomAlphaOfLengthBetween(10, 20)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SqlClearCursorRequest createTestInstance() {
|
||||
return new SqlClearCursorRequest(testMode, randomAlphaOfLength(100));
|
||||
return new SqlClearCursorRequest(requestInfo, randomAlphaOfLength(100));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,20 +39,23 @@ public class SqlClearCursorRequestTests extends AbstractSerializingTestCase<SqlC
|
|||
|
||||
@Override
|
||||
protected SqlClearCursorRequest doParseInstance(XContentParser parser) {
|
||||
return SqlClearCursorRequest.fromXContent(parser, testMode);
|
||||
return SqlClearCursorRequest.fromXContent(parser);
|
||||
}
|
||||
|
||||
private RequestInfo randomRequestInfo() {
|
||||
return new RequestInfo(randomFrom(Mode.values()), randomFrom(randomFrom(CLIENT_IDS), requestInfo.clientId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SqlClearCursorRequest mutateInstance(SqlClearCursorRequest instance) throws IOException {
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<SqlClearCursorRequest> mutator = randomFrom(
|
||||
request -> request.mode(randomValueOtherThan(request.mode(), () -> randomFrom(Mode.values()))),
|
||||
request -> request.requestInfo(randomValueOtherThan(request.requestInfo(), this::randomRequestInfo)),
|
||||
request -> request.setCursor(randomValueOtherThan(request.getCursor(), SqlQueryResponseTests::randomStringCursor))
|
||||
);
|
||||
SqlClearCursorRequest newRequest = new SqlClearCursorRequest(instance.mode(), instance.getCursor());
|
||||
SqlClearCursorRequest newRequest = new SqlClearCursorRequest(instance.requestInfo(), instance.getCursor());
|
||||
mutator.accept(newRequest);
|
||||
return newRequest;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,18 +27,16 @@ import java.util.function.Supplier;
|
|||
|
||||
import static org.elasticsearch.xpack.sql.action.SqlTestUtils.randomFilter;
|
||||
import static org.elasticsearch.xpack.sql.action.SqlTestUtils.randomFilterOrNull;
|
||||
import static org.elasticsearch.xpack.sql.proto.RequestInfo.CLI;
|
||||
import static org.elasticsearch.xpack.sql.proto.RequestInfo.CANVAS;
|
||||
import static org.elasticsearch.xpack.sql.proto.RequestInfo.CLIENT_IDS;
|
||||
|
||||
public class SqlQueryRequestTests extends AbstractSerializingTestCase<SqlQueryRequest> {
|
||||
|
||||
public RequestInfo requestInfo;
|
||||
public String clientId;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
clientId = randomFrom(CLI, CANVAS, randomAlphaOfLengthBetween(10, 20));
|
||||
requestInfo = new RequestInfo(randomFrom(Mode.values()), clientId);
|
||||
requestInfo = new RequestInfo(randomFrom(Mode.values()),
|
||||
randomFrom(randomFrom(CLIENT_IDS), randomAlphaOfLengthBetween(10, 20)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +60,7 @@ public class SqlQueryRequestTests extends AbstractSerializingTestCase<SqlQueryRe
|
|||
}
|
||||
|
||||
private RequestInfo randomRequestInfo() {
|
||||
return new RequestInfo(randomFrom(Mode.values()), randomFrom(CLI, CANVAS, clientId));
|
||||
return new RequestInfo(randomFrom(Mode.values()), randomFrom(randomFrom(CLIENT_IDS), requestInfo.clientId()));
|
||||
}
|
||||
|
||||
public List<SqlTypedParamValue> randomParameters() {
|
||||
|
@ -96,7 +94,7 @@ public class SqlQueryRequestTests extends AbstractSerializingTestCase<SqlQueryRe
|
|||
|
||||
@Override
|
||||
protected SqlQueryRequest doParseInstance(XContentParser parser) {
|
||||
return SqlQueryRequest.fromXContent(parser, requestInfo);
|
||||
return SqlQueryRequest.fromXContent(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -25,6 +26,7 @@ import java.util.function.Supplier;
|
|||
|
||||
import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.elasticsearch.xpack.sql.action.AbstractSqlQueryRequest.CURSOR;
|
||||
|
||||
public class SqlQueryResponseTests extends AbstractStreamableXContentTestCase<SqlQueryResponse> {
|
||||
|
||||
|
@ -34,10 +36,10 @@ public class SqlQueryResponseTests extends AbstractStreamableXContentTestCase<Sq
|
|||
|
||||
@Override
|
||||
protected SqlQueryResponse createTestInstance() {
|
||||
return createRandomInstance(randomStringCursor());
|
||||
return createRandomInstance(randomStringCursor(), randomFrom(Mode.values()));
|
||||
}
|
||||
|
||||
public static SqlQueryResponse createRandomInstance(String cursor) {
|
||||
public static SqlQueryResponse createRandomInstance(String cursor, Mode mode) {
|
||||
int columnCount = between(1, 10);
|
||||
|
||||
List<ColumnInfo> columns = null;
|
||||
|
@ -69,7 +71,7 @@ public class SqlQueryResponseTests extends AbstractStreamableXContentTestCase<Sq
|
|||
rows.add(row);
|
||||
}
|
||||
}
|
||||
return new SqlQueryResponse(cursor, columns, rows);
|
||||
return new SqlQueryResponse(cursor, mode, columns, rows);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,7 +110,7 @@ public class SqlQueryResponseTests extends AbstractStreamableXContentTestCase<Sq
|
|||
}
|
||||
|
||||
if (testInstance.cursor().equals("") == false) {
|
||||
assertEquals(rootMap.get(SqlQueryRequest.CURSOR.getPreferredName()), testInstance.cursor());
|
||||
assertEquals(rootMap.get(CURSOR.getPreferredName()), testInstance.cursor());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,6 +118,6 @@ public class SqlQueryResponseTests extends AbstractStreamableXContentTestCase<Sq
|
|||
protected SqlQueryResponse doParseInstance(XContentParser parser) {
|
||||
org.elasticsearch.xpack.sql.proto.SqlQueryResponse response =
|
||||
org.elasticsearch.xpack.sql.proto.SqlQueryResponse.fromXContent(parser);
|
||||
return new SqlQueryResponse(response.cursor(), response.columns(), response.rows());
|
||||
return new SqlQueryResponse(response.cursor(), Mode.JDBC, response.columns(), response.rows());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.sql.action;
|
||||
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class SqlRequestParsersTests extends ESTestCase {
|
||||
|
||||
public void testUnknownFieldParsingErrors() throws IOException {
|
||||
assertParsingErrorMessage("{\"key\" : \"value\"}", "unknown field [key]", SqlClearCursorRequest::fromXContent);
|
||||
assertParsingErrorMessage("{\"key\" : \"value\"}", "unknown field [key]", SqlQueryRequest::fromXContent);
|
||||
assertParsingErrorMessage("{\"key\" : \"value\"}", "unknown field [key]", SqlTranslateRequest::fromXContent);
|
||||
}
|
||||
|
||||
public void testUnknownModeFieldParsingErrors() throws IOException {
|
||||
assertParsingErrorMessageReason("{\"cursor\":\"foo\",\"mode\" : \"value\"}",
|
||||
"No enum constant org.elasticsearch.xpack.sql.proto.Mode.VALUE", SqlClearCursorRequest::fromXContent);
|
||||
assertParsingErrorMessageReason("{\"cursor\":\"foo\",\"mode\" : \"value\"}",
|
||||
"No enum constant org.elasticsearch.xpack.sql.proto.Mode.VALUE", SqlQueryRequest::fromXContent);
|
||||
assertParsingErrorMessageReason("{\"mode\" : \"value\"}",
|
||||
"No enum constant org.elasticsearch.xpack.sql.proto.Mode.VALUE", SqlTranslateRequest::fromXContent);
|
||||
}
|
||||
|
||||
public void testClearCursorRequestParser() throws IOException {
|
||||
assertParsingErrorMessage("{\"mode\" : \"jdbc\"}", "Required [cursor]", SqlClearCursorRequest::fromXContent);
|
||||
assertParsingErrorMessage("{\"cursor\" : \"whatever\", \"fetch_size\":123}", "unknown field [fetch_size]",
|
||||
SqlClearCursorRequest::fromXContent);
|
||||
Mode randomMode = randomFrom(Mode.values());
|
||||
|
||||
SqlClearCursorRequest request = generateRequest("{\"cursor\" : \"whatever\", \"mode\" : \""
|
||||
+ randomMode.toString() + "\", \"client_id\" : \"bla\"}",
|
||||
SqlClearCursorRequest::fromXContent);
|
||||
assertNull(request.clientId());
|
||||
assertEquals(randomMode, request.mode());
|
||||
assertEquals("whatever", request.getCursor());
|
||||
|
||||
randomMode = randomFrom(Mode.values());
|
||||
request = generateRequest("{\"cursor\" : \"whatever\", \"mode\" : \""
|
||||
+ randomMode.toString() + "\", \"client_id\" : \"bla\"}",
|
||||
SqlClearCursorRequest::fromXContent);
|
||||
assertNull(request.clientId());
|
||||
assertEquals(randomMode, request.mode());
|
||||
assertEquals("whatever", request.getCursor());
|
||||
|
||||
request = generateRequest("{\"cursor\" : \"whatever\"}", SqlClearCursorRequest::fromXContent);
|
||||
assertNull(request.clientId());
|
||||
assertEquals(Mode.PLAIN, request.mode());
|
||||
assertEquals("whatever", request.getCursor());
|
||||
|
||||
request = generateRequest("{\"cursor\" : \"whatever\", \"client_id\" : \"CLI\"}",
|
||||
SqlClearCursorRequest::fromXContent);
|
||||
assertEquals("cli", request.clientId());
|
||||
assertEquals(Mode.PLAIN, request.mode());
|
||||
assertEquals("whatever", request.getCursor());
|
||||
|
||||
request = generateRequest("{\"cursor\" : \"whatever\", \"client_id\" : \"cANVAs\"}",
|
||||
SqlClearCursorRequest::fromXContent);
|
||||
assertEquals("canvas", request.clientId());
|
||||
assertEquals(Mode.PLAIN, request.mode());
|
||||
assertEquals("whatever", request.getCursor());
|
||||
}
|
||||
|
||||
public void testTranslateRequestParser() throws IOException {
|
||||
assertParsingErrorMessage("{\"qquery\" : \"select * from bla\"}", "unknown field [qquery]", SqlTranslateRequest::fromXContent);
|
||||
|
||||
SqlTranslateRequest request = generateRequest("{\"query\" : \"select * from foo\"}", SqlTranslateRequest::fromXContent);
|
||||
assertEquals("select * from foo", request.query());
|
||||
assertEquals(Mode.PLAIN, request.mode());
|
||||
|
||||
Mode randomMode = randomFrom(Mode.values());
|
||||
request = generateRequest("{\"query\" : \"whatever\", \"client_id\" : \"foo\", \"mode\":\""
|
||||
+ randomMode.toString() + "\"}",
|
||||
SqlTranslateRequest::fromXContent);
|
||||
assertNull(request.clientId());
|
||||
assertEquals(randomMode, request.mode());
|
||||
}
|
||||
|
||||
public void testQueryRequestParser() throws IOException {
|
||||
assertParsingErrorMessage("{\"mode\" : 123}", "mode doesn't support values of type: VALUE_NUMBER", SqlQueryRequest::fromXContent);
|
||||
assertParsingErrorMessage("{\"cursor\" : \"whatever\", \"fetch_size\":\"abc\"}", "failed to parse field [fetch_size]",
|
||||
SqlQueryRequest::fromXContent);
|
||||
assertParsingErrorMessage("{\"client_id\":123}", "client_id doesn't support values of type: VALUE_NUMBER",
|
||||
SqlQueryRequest::fromXContent);
|
||||
assertParsingErrorMessage("{\"params\":[{\"value\":123}]}", "failed to parse field [params]", SqlQueryRequest::fromXContent);
|
||||
assertParsingErrorMessage("{\"time_zone\":12}", "time_zone doesn't support values of type: VALUE_NUMBER",
|
||||
SqlQueryRequest::fromXContent);
|
||||
|
||||
Mode randomMode = randomFrom(Mode.values());
|
||||
SqlQueryRequest request = generateRequest("{\"cursor\" : \"whatever\", \"mode\" : \""
|
||||
+ randomMode.toString() + "\", \"client_id\" : \"bla\","
|
||||
+ "\"query\":\"select\",\"params\":[{\"value\":123, \"type\":\"whatever\"}], \"time_zone\":\"UTC\","
|
||||
+ "\"request_timeout\":\"5s\",\"page_timeout\":\"10s\"}", SqlQueryRequest::fromXContent);
|
||||
assertNull(request.clientId());
|
||||
assertEquals(randomMode, request.mode());
|
||||
assertEquals("whatever", request.cursor());
|
||||
assertEquals("select", request.query());
|
||||
|
||||
List<SqlTypedParamValue> list = new ArrayList<SqlTypedParamValue>(1);
|
||||
list.add(new SqlTypedParamValue("whatever", 123));
|
||||
assertEquals(list, request.params());
|
||||
assertEquals("UTC", request.timeZone().getID());
|
||||
assertEquals(TimeValue.parseTimeValue("5s", "request_timeout"), request.requestTimeout());
|
||||
assertEquals(TimeValue.parseTimeValue("10s", "page_timeout"), request.pageTimeout());
|
||||
}
|
||||
|
||||
private <R extends AbstractSqlRequest> R generateRequest(String json, Function<XContentParser, R> fromXContent)
|
||||
throws IOException {
|
||||
XContentParser parser = parser(json);
|
||||
return fromXContent.apply(parser);
|
||||
}
|
||||
|
||||
private void assertParsingErrorMessage(String json, String errorMessage, Consumer<XContentParser> consumer) throws IOException {
|
||||
XContentParser parser = parser(json);
|
||||
Exception e = expectThrows(IllegalArgumentException.class, () -> consumer.accept(parser));
|
||||
assertThat(e.getMessage(), containsString(errorMessage));
|
||||
}
|
||||
|
||||
private void assertParsingErrorMessageReason(String json, String errorMessage, Consumer<XContentParser> consumer) throws IOException {
|
||||
XContentParser parser = parser(json);
|
||||
Exception e = expectThrows(IllegalArgumentException.class, () -> consumer.accept(parser));
|
||||
assertThat(e.getCause().getMessage(), containsString(errorMessage));
|
||||
}
|
||||
|
||||
private XContentParser parser(String content) throws IOException {
|
||||
XContentType xContentType = XContentType.JSON;
|
||||
return xContentType.xContent().createParser(
|
||||
NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, content);
|
||||
}
|
||||
}
|
|
@ -63,7 +63,7 @@ public class SqlTranslateRequestTests extends AbstractSerializingTestCase<SqlTra
|
|||
|
||||
@Override
|
||||
protected SqlTranslateRequest doParseInstance(XContentParser parser) {
|
||||
return SqlTranslateRequest.fromXContent(parser, testMode);
|
||||
return SqlTranslateRequest.fromXContent(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -50,7 +50,7 @@ public class ConnectionConfiguration {
|
|||
public static final String PAGE_SIZE = "page.size";
|
||||
private static final String PAGE_SIZE_DEFAULT = "1000";
|
||||
|
||||
public static final String CLIENT_ID = "client.id";
|
||||
public static final String CLIENT_ID = "client_id";
|
||||
|
||||
// Auth
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ import org.elasticsearch.xpack.sql.proto.AbstractSqlRequest;
|
|||
import org.elasticsearch.xpack.sql.proto.MainResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
import org.elasticsearch.xpack.sql.proto.RequestInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlClearCursorRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlClearCursorResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.RequestInfo;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
@ -37,7 +37,6 @@ import java.util.TimeZone;
|
|||
import java.util.function.Function;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.proto.RequestInfo.CLI;
|
||||
import static org.elasticsearch.xpack.sql.client.ConnectionConfiguration.CLIENT_ID;
|
||||
|
||||
/**
|
||||
* A specialized high-level REST client with support for SQL-related functions.
|
||||
|
@ -66,7 +65,7 @@ public class HttpClient {
|
|||
|
||||
public SqlQueryResponse queryInit(String query, int fetchSize) throws SQLException {
|
||||
// TODO allow customizing the time zone - this is what session set/reset/get should be about
|
||||
// method called only from CLI. "client.id" is set to "cli"
|
||||
// method called only from CLI. "client_id" is set to "cli"
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(query, Collections.emptyList(), null, TimeZone.getTimeZone("UTC"),
|
||||
fetchSize, TimeValue.timeValueMillis(cfg.queryTimeout()), TimeValue.timeValueMillis(cfg.pageTimeout()),
|
||||
new RequestInfo(Mode.PLAIN, CLI));
|
||||
|
@ -78,7 +77,7 @@ public class HttpClient {
|
|||
}
|
||||
|
||||
public SqlQueryResponse nextPage(String cursor) throws SQLException {
|
||||
// method called only from CLI. "client.id" is set to "cli"
|
||||
// method called only from CLI. "client_id" is set to "cli"
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(cursor, TimeValue.timeValueMillis(cfg.queryTimeout()),
|
||||
TimeValue.timeValueMillis(cfg.pageTimeout()), new RequestInfo(Mode.PLAIN, CLI));
|
||||
return post(Protocol.SQL_QUERY_REST_ENDPOINT, sqlRequest, SqlQueryResponse::fromXContent);
|
||||
|
@ -95,9 +94,7 @@ public class HttpClient {
|
|||
CheckedFunction<XContentParser, Response, IOException> responseParser)
|
||||
throws SQLException {
|
||||
byte[] requestBytes = toXContent(request);
|
||||
String query = "error_trace&mode=" +
|
||||
request.mode() +
|
||||
(request.clientId() != null ? "&" + CLIENT_ID + "=" + request.clientId() : "");
|
||||
String query = "error_trace";
|
||||
Tuple<XContentType, byte[]> response =
|
||||
AccessController.doPrivileged((PrivilegedAction<ResponseOrException<Tuple<XContentType, byte[]>>>) () ->
|
||||
JreHttpUrlConnection.http(path, query, cfg, con ->
|
||||
|
|
|
@ -17,7 +17,7 @@ public enum Mode {
|
|||
ODBC;
|
||||
|
||||
public static Mode fromString(String mode) {
|
||||
if (mode == null) {
|
||||
if (mode == null || mode.isEmpty()) {
|
||||
return PLAIN;
|
||||
}
|
||||
return Mode.valueOf(mode.toUpperCase(Locale.ROOT));
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
|
||||
package org.elasticsearch.xpack.sql.proto;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
public class RequestInfo {
|
||||
public static final String CLI = "cli";
|
||||
public static final String CANVAS = "canvas";
|
||||
private static final String CANVAS = "canvas";
|
||||
public static final List<String> CLIENT_IDS = Arrays.asList(CLI, CANVAS);
|
||||
|
||||
private Mode mode;
|
||||
private String clientId;
|
||||
|
@ -20,8 +24,8 @@ public class RequestInfo {
|
|||
}
|
||||
|
||||
public RequestInfo(Mode mode, String clientId) {
|
||||
this.mode = mode;
|
||||
this.clientId = clientId;
|
||||
mode(mode);
|
||||
clientId(clientId);
|
||||
}
|
||||
|
||||
public Mode mode() {
|
||||
|
@ -37,6 +41,12 @@ public class RequestInfo {
|
|||
}
|
||||
|
||||
public void clientId(String clientId) {
|
||||
if (clientId != null) {
|
||||
clientId = clientId.toLowerCase(Locale.ROOT);
|
||||
if (false == CLIENT_IDS.contains(clientId)) {
|
||||
clientId = null;
|
||||
}
|
||||
}
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,10 @@ public class SqlClearCursorRequest extends AbstractSqlRequest {
|
|||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.field("cursor", cursor);
|
||||
builder.field("mode", mode().toString());
|
||||
if (clientId() != null) {
|
||||
builder.field("client_id", clientId());
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,6 +140,10 @@ public class SqlQueryRequest extends AbstractSqlRequest {
|
|||
if (query != null) {
|
||||
builder.field("query", query);
|
||||
}
|
||||
builder.field("mode", mode().toString());
|
||||
if (clientId() != null) {
|
||||
builder.field("client_id", clientId());
|
||||
}
|
||||
if (this.params.isEmpty() == false) {
|
||||
builder.startArray("params");
|
||||
for (SqlTypedParamValue val : this.params) {
|
||||
|
|
|
@ -24,6 +24,8 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
|
|||
|
||||
public final class StringUtils {
|
||||
|
||||
public static final String EMPTY = "";
|
||||
|
||||
private static final DateTimeFormatter ISO_WITH_MILLIS = new DateTimeFormatterBuilder()
|
||||
.parseCaseInsensitive()
|
||||
.append(ISO_LOCAL_DATE)
|
||||
|
|
|
@ -17,7 +17,6 @@ import org.elasticsearch.rest.RestRequest;
|
|||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
import org.elasticsearch.xpack.sql.action.SqlClearCursorAction;
|
||||
import org.elasticsearch.xpack.sql.action.SqlClearCursorRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -37,11 +36,13 @@ public class RestSqlClearCursorAction extends BaseRestHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client)
|
||||
throws IOException {
|
||||
SqlClearCursorRequest sqlRequest;
|
||||
try (XContentParser parser = request.contentOrSourceParamParser()) {
|
||||
sqlRequest = SqlClearCursorRequest.fromXContent(parser, Mode.fromString(request.param("mode")));
|
||||
try (XContentParser parser = request.contentParser()) {
|
||||
sqlRequest = SqlClearCursorRequest.fromXContent(parser);
|
||||
}
|
||||
|
||||
return channel -> client.executeLocally(SqlClearCursorAction.INSTANCE, sqlRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,27 +24,20 @@ import org.elasticsearch.rest.action.RestResponseListener;
|
|||
import org.elasticsearch.xpack.sql.action.SqlQueryAction;
|
||||
import org.elasticsearch.xpack.sql.action.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.action.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
import org.elasticsearch.xpack.sql.proto.RequestInfo;
|
||||
import org.elasticsearch.xpack.sql.session.Cursor;
|
||||
import org.elasticsearch.xpack.sql.session.Cursors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.xpack.sql.proto.RequestInfo.CANVAS;
|
||||
import static org.elasticsearch.xpack.sql.proto.RequestInfo.CLI;
|
||||
|
||||
public class RestSqlQueryAction extends BaseRestHandler {
|
||||
|
||||
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(RestSqlQueryAction.class));
|
||||
|
||||
private static String CLIENT_ID = "client.id";
|
||||
|
||||
RestSqlQueryAction(Settings settings, RestController controller) {
|
||||
super(settings);
|
||||
// TODO: remove deprecated endpoint in 8.0.0
|
||||
|
@ -58,21 +51,13 @@ public class RestSqlQueryAction extends BaseRestHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client)
|
||||
throws IOException {
|
||||
SqlQueryRequest sqlRequest;
|
||||
try (XContentParser parser = request.contentOrSourceParamParser()) {
|
||||
String clientId = request.param(CLIENT_ID);
|
||||
if (clientId != null) {
|
||||
clientId = clientId.toLowerCase(Locale.ROOT);
|
||||
if (!clientId.equals(CLI) && !clientId.equals(CANVAS)) {
|
||||
clientId = null;
|
||||
}
|
||||
}
|
||||
|
||||
sqlRequest = SqlQueryRequest.fromXContent(parser,
|
||||
new RequestInfo(Mode.fromString(request.param("mode")), clientId));
|
||||
sqlRequest = SqlQueryRequest.fromXContent(parser);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Since we support {@link TextFormat} <strong>and</strong>
|
||||
* {@link XContent} outputs we can't use {@link RestToXContentListener}
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.elasticsearch.rest.RestRequest;
|
|||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
import org.elasticsearch.xpack.sql.action.SqlTranslateAction;
|
||||
import org.elasticsearch.xpack.sql.action.SqlTranslateRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -44,11 +43,13 @@ public class RestSqlTranslateAction extends BaseRestHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client)
|
||||
throws IOException {
|
||||
SqlTranslateRequest sqlRequest;
|
||||
try (XContentParser parser = request.contentOrSourceParamParser()) {
|
||||
sqlRequest = SqlTranslateRequest.fromXContent(parser, Mode.fromString(request.param("mode")));
|
||||
sqlRequest = SqlTranslateRequest.fromXContent(parser);
|
||||
}
|
||||
|
||||
return channel -> client.executeLocally(SqlTranslateAction.INSTANCE, sqlRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ public class TransportSqlQueryAction extends HandledTransportAction<SqlQueryRequ
|
|||
} else {
|
||||
planExecutor.metrics().paging(metric);
|
||||
planExecutor.nextPage(cfg, Cursors.decodeFromString(request.cursor()),
|
||||
ActionListener.wrap(rowSet -> listener.onResponse(createResponse(rowSet, null)),
|
||||
ActionListener.wrap(rowSet -> listener.onResponse(createResponse(request.mode(), rowSet, null)),
|
||||
e -> {
|
||||
planExecutor.metrics().failed(metric);
|
||||
listener.onFailure(e);
|
||||
|
@ -107,10 +107,10 @@ public class TransportSqlQueryAction extends HandledTransportAction<SqlQueryRequ
|
|||
}
|
||||
}
|
||||
columns = unmodifiableList(columns);
|
||||
return createResponse(rowSet, columns);
|
||||
return createResponse(request.mode(), rowSet, columns);
|
||||
}
|
||||
|
||||
static SqlQueryResponse createResponse(RowSet rowSet, List<ColumnInfo> columns) {
|
||||
static SqlQueryResponse createResponse(Mode mode, RowSet rowSet, List<ColumnInfo> columns) {
|
||||
List<List<Object>> rows = new ArrayList<>();
|
||||
rowSet.forEachRow(rowView -> {
|
||||
List<Object> row = new ArrayList<>(rowView.columnCount());
|
||||
|
@ -120,6 +120,7 @@ public class TransportSqlQueryAction extends HandledTransportAction<SqlQueryRequ
|
|||
|
||||
return new SqlQueryResponse(
|
||||
Cursors.encodeToString(Version.CURRENT, rowSet.nextPageCursor()),
|
||||
mode,
|
||||
columns,
|
||||
rows);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.sql.action;
|
|||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
|
@ -14,7 +15,7 @@ import java.util.Arrays;
|
|||
import static org.hamcrest.Matchers.arrayWithSize;
|
||||
|
||||
public class CliFormatterTests extends ESTestCase {
|
||||
private final SqlQueryResponse firstResponse = new SqlQueryResponse("",
|
||||
private final SqlQueryResponse firstResponse = new SqlQueryResponse("", Mode.PLAIN,
|
||||
Arrays.asList(
|
||||
new ColumnInfo("", "foo", "string", Types.VARCHAR, 0),
|
||||
new ColumnInfo("", "bar", "long", Types.BIGINT, 15),
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.xpack.sql.action.CliFormatter;
|
|||
import org.elasticsearch.xpack.sql.action.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.plugin.CliFormatterCursor;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.session.Configuration;
|
||||
import org.elasticsearch.xpack.sql.session.Cursor;
|
||||
import org.elasticsearch.xpack.sql.session.Cursors;
|
||||
|
@ -69,7 +70,7 @@ public class CursorTests extends ESTestCase {
|
|||
randomInt(), randomInt(25)));
|
||||
}
|
||||
}
|
||||
return new SqlQueryResponse("", columns, Collections.emptyList());
|
||||
return new SqlQueryResponse("", randomFrom(Mode.values()), columns, Collections.emptyList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.test.ESTestCase;
|
|||
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||
import org.elasticsearch.xpack.sql.action.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -117,7 +118,7 @@ public class TextFormatTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private static SqlQueryResponse emptyData() {
|
||||
return new SqlQueryResponse(null, singletonList(new ColumnInfo("index", "name", "keyword")), emptyList());
|
||||
return new SqlQueryResponse(null, Mode.JDBC, singletonList(new ColumnInfo("index", "name", "keyword")), emptyList());
|
||||
}
|
||||
|
||||
private static SqlQueryResponse regularData() {
|
||||
|
@ -131,7 +132,7 @@ public class TextFormatTests extends ESTestCase {
|
|||
values.add(asList("Along The River Bank", 11 * 60 + 48));
|
||||
values.add(asList("Mind Train", 4 * 60 + 40));
|
||||
|
||||
return new SqlQueryResponse(null, headers, values);
|
||||
return new SqlQueryResponse(null, Mode.JDBC, headers, values);
|
||||
}
|
||||
|
||||
private static SqlQueryResponse escapedData() {
|
||||
|
@ -145,7 +146,7 @@ public class TextFormatTests extends ESTestCase {
|
|||
values.add(asList("normal", "\"quo\"ted\",\n"));
|
||||
values.add(asList("commas", "a,b,c,\n,d,e,\t\n"));
|
||||
|
||||
return new SqlQueryResponse(null, headers, values);
|
||||
return new SqlQueryResponse(null, Mode.JDBC, headers, values);
|
||||
}
|
||||
|
||||
private static RestRequest req() {
|
||||
|
|
Loading…
Reference in New Issue