SQL: Extract SQL request and response classes (#30457)
Extracts SQL request and response classes. This is the first step towards creation of a small minimal dependencies jdbc driver. Relates #29856
This commit is contained in:
parent
4e33443690
commit
56d32bc8b2
|
@ -43,6 +43,10 @@ public class JdbcConnection implements Connection, JdbcWrapper {
|
|||
private String catalog;
|
||||
private String schema;
|
||||
|
||||
/**
|
||||
* The SQLException is the only type of Exception the JDBC API can throw (and that the user expects).
|
||||
* If we remove it, we need to make sure no other types of Exceptions (runtime or otherwise) are thrown
|
||||
*/
|
||||
public JdbcConnection(JdbcConfiguration connectionInfo) throws SQLException {
|
||||
cfg = connectionInfo;
|
||||
client = new JdbcHttpClient(connectionInfo);
|
||||
|
|
|
@ -7,7 +7,7 @@ package org.elasticsearch.xpack.sql.jdbc.jdbc;
|
|||
|
||||
import org.elasticsearch.xpack.sql.jdbc.net.client.Cursor;
|
||||
import org.elasticsearch.xpack.sql.jdbc.net.client.RequestMeta;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
package org.elasticsearch.xpack.sql.jdbc.jdbc;
|
||||
|
||||
import org.elasticsearch.xpack.sql.jdbc.JdbcSQLException;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.sql.JDBCType;
|
||||
|
@ -73,7 +73,7 @@ class PreparedQuery {
|
|||
*/
|
||||
List<SqlTypedParamValue> params() {
|
||||
return Arrays.stream(this.params).map(
|
||||
paramInfo -> new SqlTypedParamValue(paramInfo.value, DataType.fromJdbcType(paramInfo.type))
|
||||
paramInfo -> new SqlTypedParamValue(DataType.fromJdbcType(paramInfo.type), paramInfo.value)
|
||||
).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
|
|
@ -5,22 +5,21 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.sql.jdbc.net.client;
|
||||
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.xpack.sql.client.HttpClient;
|
||||
import org.elasticsearch.xpack.sql.jdbc.jdbc.JdbcConfiguration;
|
||||
import org.elasticsearch.xpack.sql.jdbc.net.protocol.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.jdbc.net.protocol.InfoResponse;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.MainResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.client.shared.StringUtils.EMPTY;
|
||||
|
@ -34,6 +33,10 @@ public class JdbcHttpClient {
|
|||
private final JdbcConfiguration conCfg;
|
||||
private InfoResponse serverInfo;
|
||||
|
||||
/**
|
||||
* The SQLException is the only type of Exception the JDBC API can throw (and that the user expects).
|
||||
* If we remove it, we need to make sure no other types of Exceptions (runtime or otherwise) are thrown
|
||||
*/
|
||||
public JdbcHttpClient(JdbcConfiguration conCfg) throws SQLException {
|
||||
httpClient = new HttpClient(conCfg);
|
||||
this.conCfg = conCfg;
|
||||
|
@ -45,9 +48,9 @@ public class JdbcHttpClient {
|
|||
|
||||
public Cursor query(String sql, List<SqlTypedParamValue> params, RequestMeta meta) throws SQLException {
|
||||
int fetch = meta.fetchSize() > 0 ? meta.fetchSize() : conCfg.pageSize();
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(AbstractSqlRequest.Mode.JDBC, sql, params, null,
|
||||
AbstractSqlQueryRequest.DEFAULT_TIME_ZONE,
|
||||
fetch, TimeValue.timeValueMillis(meta.timeoutInMs()), TimeValue.timeValueMillis(meta.queryTimeoutInMs()), "");
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(Mode.JDBC, sql, params, null,
|
||||
Protocol.TIME_ZONE,
|
||||
fetch, TimeValue.timeValueMillis(meta.timeoutInMs()), TimeValue.timeValueMillis(meta.queryTimeoutInMs()));
|
||||
SqlQueryResponse response = httpClient.query(sqlRequest);
|
||||
return new DefaultCursor(this, response.cursor(), toJdbcColumnInfo(response.columns()), response.rows(), meta);
|
||||
}
|
||||
|
@ -57,10 +60,8 @@ public class JdbcHttpClient {
|
|||
* the scroll id to use to fetch the next page.
|
||||
*/
|
||||
public Tuple<String, List<List<Object>>> nextPage(String cursor, RequestMeta meta) throws SQLException {
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest().cursor(cursor);
|
||||
sqlRequest.mode(AbstractSqlRequest.Mode.JDBC);
|
||||
sqlRequest.requestTimeout(TimeValue.timeValueMillis(meta.timeoutInMs()));
|
||||
sqlRequest.pageTimeout(TimeValue.timeValueMillis(meta.queryTimeoutInMs()));
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(Mode.JDBC, cursor, TimeValue.timeValueMillis(meta.timeoutInMs()),
|
||||
TimeValue.timeValueMillis(meta.queryTimeoutInMs()));
|
||||
SqlQueryResponse response = httpClient.query(sqlRequest);
|
||||
return new Tuple<>(response.cursor(), response.rows());
|
||||
}
|
||||
|
@ -78,13 +79,13 @@ public class JdbcHttpClient {
|
|||
|
||||
private InfoResponse fetchServerInfo() throws SQLException {
|
||||
MainResponse mainResponse = httpClient.serverInfo();
|
||||
return new InfoResponse(mainResponse.getClusterName().value(), mainResponse.getVersion().major, mainResponse.getVersion().minor);
|
||||
return new InfoResponse(mainResponse.getClusterName(), mainResponse.getVersion().major, mainResponse.getVersion().minor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts REST column metadata into JDBC column metadata
|
||||
*/
|
||||
private List<ColumnInfo> toJdbcColumnInfo(List<org.elasticsearch.xpack.sql.plugin.ColumnInfo> columns) {
|
||||
private List<ColumnInfo> toJdbcColumnInfo(List<org.elasticsearch.xpack.sql.proto.ColumnInfo> columns) {
|
||||
return columns.stream().map(columnInfo ->
|
||||
new ColumnInfo(columnInfo.name(), columnInfo.jdbcType(), EMPTY, EMPTY, EMPTY, EMPTY, columnInfo.displaySize())
|
||||
).collect(Collectors.toList());
|
||||
|
|
|
@ -10,8 +10,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.sql.JDBCType;
|
||||
|
@ -51,7 +51,7 @@ public class TypeConverterTests extends ESTestCase {
|
|||
XContentBuilder builder = JsonXContent.contentBuilder();
|
||||
builder.startObject();
|
||||
builder.field("value");
|
||||
SqlQueryResponse.value(builder, AbstractSqlRequest.Mode.JDBC, value);
|
||||
SqlQueryResponse.value(builder, Mode.JDBC, value);
|
||||
builder.endObject();
|
||||
builder.close();
|
||||
Object copy = XContentHelper.convertToMap(BytesReference.bytes(builder), false, builder.contentType()).v2().get("value");
|
||||
|
|
|
@ -5,11 +5,12 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.sql.cli.command;
|
||||
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.xpack.sql.client.HttpClient;
|
||||
import org.elasticsearch.xpack.sql.client.shared.ClientException;
|
||||
import org.elasticsearch.xpack.sql.client.shared.Version;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.MainResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
@ -18,7 +19,7 @@ import java.sql.SQLException;
|
|||
*/
|
||||
public class CliSession {
|
||||
private final HttpClient httpClient;
|
||||
private int fetchSize = AbstractSqlQueryRequest.DEFAULT_FETCH_SIZE;
|
||||
private int fetchSize = Protocol.FETCH_SIZE;
|
||||
private String fetchSeparator = "";
|
||||
private boolean debug;
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.sql.cli.command;
|
||||
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.xpack.sql.cli.CliTerminal;
|
||||
import org.elasticsearch.xpack.sql.proto.MainResponse;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
|
@ -30,7 +30,7 @@ public class ServerInfoCliCommand extends AbstractServerCliCommand {
|
|||
}
|
||||
terminal.line()
|
||||
.text("Node:").em(info.getNodeName())
|
||||
.text(" Cluster:").em(info.getClusterName().value())
|
||||
.text(" Cluster:").em(info.getClusterName())
|
||||
.text(" Version:").em(info.getVersion().toString())
|
||||
.ln();
|
||||
return true;
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.elasticsearch.xpack.sql.cli.CliTerminal;
|
|||
import org.elasticsearch.xpack.sql.client.HttpClient;
|
||||
import org.elasticsearch.xpack.sql.client.shared.JreHttpUrlConnection;
|
||||
import org.elasticsearch.xpack.sql.plugin.CliFormatter;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryResponse;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
@ -23,8 +23,8 @@ public class ServerQueryCliCommand extends AbstractServerCliCommand {
|
|||
String data;
|
||||
try {
|
||||
response = cliClient.queryInit(line, cliSession.getFetchSize());
|
||||
cliFormatter = new CliFormatter(response);
|
||||
data = cliFormatter.formatWithHeader(response);
|
||||
cliFormatter = new CliFormatter(response.columns(), response.rows());
|
||||
data = cliFormatter.formatWithHeader(response.columns(), response.rows());
|
||||
while (true) {
|
||||
handleText(terminal, data);
|
||||
if (response.cursor().isEmpty()) {
|
||||
|
@ -36,7 +36,7 @@ public class ServerQueryCliCommand extends AbstractServerCliCommand {
|
|||
terminal.println(cliSession.getFetchSeparator());
|
||||
}
|
||||
response = cliSession.getClient().nextPage(response.cursor());
|
||||
data = cliFormatter.formatWithoutHeader(response);
|
||||
data = cliFormatter.formatWithoutHeader(response.rows());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
if (JreHttpUrlConnection.SQL_STATE_BAD_SERVER.equals(e.getSQLState())) {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
package org.elasticsearch.xpack.sql.cli;
|
||||
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.common.UUIDs;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
@ -14,6 +13,7 @@ import org.elasticsearch.xpack.sql.cli.command.CliSession;
|
|||
import org.elasticsearch.xpack.sql.client.HttpClient;
|
||||
import org.elasticsearch.xpack.sql.client.shared.ClientException;
|
||||
import org.elasticsearch.xpack.sql.client.shared.Version;
|
||||
import org.elasticsearch.xpack.sql.proto.MainResponse;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
@ -28,7 +28,7 @@ public class CliSessionTests extends ESTestCase {
|
|||
public void testProperConnection() throws Exception {
|
||||
HttpClient httpClient = mock(HttpClient.class);
|
||||
when(httpClient.serverInfo()).thenReturn(new MainResponse(randomAlphaOfLength(5), org.elasticsearch.Version.CURRENT,
|
||||
ClusterName.DEFAULT, UUIDs.randomBase64UUID(), Build.CURRENT));
|
||||
ClusterName.DEFAULT.value(), UUIDs.randomBase64UUID(), Build.CURRENT));
|
||||
CliSession cliSession = new CliSession(httpClient);
|
||||
cliSession.checkConnection();
|
||||
verify(httpClient, times(1)).serverInfo();
|
||||
|
@ -58,7 +58,7 @@ public class CliSessionTests extends ESTestCase {
|
|||
}
|
||||
when(httpClient.serverInfo()).thenReturn(new MainResponse(randomAlphaOfLength(5),
|
||||
org.elasticsearch.Version.fromString(major + "." + minor + ".23"),
|
||||
ClusterName.DEFAULT, UUIDs.randomBase64UUID(), Build.CURRENT));
|
||||
ClusterName.DEFAULT.value(), UUIDs.randomBase64UUID(), Build.CURRENT));
|
||||
CliSession cliSession = new CliSession(httpClient);
|
||||
expectThrows(ClientException.class, cliSession::checkConnection);
|
||||
verify(httpClient, times(1)).serverInfo();
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
package org.elasticsearch.xpack.sql.cli.command;
|
||||
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.common.UUIDs;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.cli.TestTerminal;
|
||||
import org.elasticsearch.xpack.sql.client.HttpClient;
|
||||
import org.elasticsearch.xpack.sql.proto.MainResponse;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
@ -36,7 +36,7 @@ public class ServerInfoCliCommandTests extends ESTestCase {
|
|||
HttpClient client = mock(HttpClient.class);
|
||||
CliSession cliSession = new CliSession(client);
|
||||
when(client.serverInfo()).thenReturn(new MainResponse("my_node", org.elasticsearch.Version.fromString("1.2.3"),
|
||||
new ClusterName("my_cluster"), UUIDs.randomBase64UUID(), Build.CURRENT));
|
||||
new ClusterName("my_cluster").value(), UUIDs.randomBase64UUID(), Build.CURRENT));
|
||||
ServerInfoCliCommand cliCommand = new ServerInfoCliCommand();
|
||||
assertTrue(cliCommand.handle(testTerminal, cliSession, "info"));
|
||||
assertEquals(testTerminal.toString(), "Node:<em>my_node</em> Cluster:<em>my_cluster</em> Version:<em>1.2.3</em>\n");
|
||||
|
|
|
@ -8,8 +8,8 @@ package org.elasticsearch.xpack.sql.cli.command;
|
|||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.cli.TestTerminal;
|
||||
import org.elasticsearch.xpack.sql.client.HttpClient;
|
||||
import org.elasticsearch.xpack.sql.plugin.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryResponse;
|
||||
|
||||
import java.sql.JDBCType;
|
||||
import java.sql.SQLException;
|
||||
|
|
|
@ -10,12 +10,17 @@ import org.elasticsearch.common.Nullable;
|
|||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentFragment;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
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.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
@ -28,20 +33,12 @@ import java.util.function.Supplier;
|
|||
* Base class for requests that contain sql queries (Query and Translate)
|
||||
*/
|
||||
public abstract class AbstractSqlQueryRequest extends AbstractSqlRequest implements CompositeIndicesRequest, ToXContentFragment {
|
||||
public static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("UTC");
|
||||
|
||||
/**
|
||||
* Global choice for the default fetch size.
|
||||
*/
|
||||
public static final int DEFAULT_FETCH_SIZE = 1000;
|
||||
public static final TimeValue DEFAULT_REQUEST_TIMEOUT = TimeValue.timeValueSeconds(90);
|
||||
public static final TimeValue DEFAULT_PAGE_TIMEOUT = TimeValue.timeValueSeconds(45);
|
||||
|
||||
private String query = "";
|
||||
private TimeZone timeZone = DEFAULT_TIME_ZONE;
|
||||
private int fetchSize = DEFAULT_FETCH_SIZE;
|
||||
private TimeValue requestTimeout = DEFAULT_REQUEST_TIMEOUT;
|
||||
private TimeValue pageTimeout = DEFAULT_PAGE_TIMEOUT;
|
||||
private TimeZone timeZone = Protocol.TIME_ZONE;
|
||||
private int fetchSize = Protocol.FETCH_SIZE;
|
||||
private TimeValue requestTimeout = Protocol.REQUEST_TIMEOUT;
|
||||
private TimeValue pageTimeout = Protocol.PAGE_TIMEOUT;
|
||||
@Nullable
|
||||
private QueryBuilder filter = null;
|
||||
private List<SqlTypedParamValue> params = Collections.emptyList();
|
||||
|
@ -69,11 +66,10 @@ public abstract class AbstractSqlQueryRequest extends AbstractSqlRequest impleme
|
|||
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"));
|
||||
parser.declareString((request, timeout) -> request.requestTimeout(TimeValue.parseTimeValue(timeout, Protocol.REQUEST_TIMEOUT,
|
||||
"request_timeout")), new ParseField("request_timeout"));
|
||||
parser.declareString(
|
||||
(request, timeout) -> request.requestTimeout(TimeValue.parseTimeValue(timeout, DEFAULT_REQUEST_TIMEOUT, "request_timeout")),
|
||||
new ParseField("request_timeout"));
|
||||
parser.declareString(
|
||||
(request, timeout) -> request.pageTimeout(TimeValue.parseTimeValue(timeout, DEFAULT_PAGE_TIMEOUT, "page_timeout")),
|
||||
(request, timeout) -> request.pageTimeout(TimeValue.parseTimeValue(timeout, Protocol.PAGE_TIMEOUT, "page_timeout")),
|
||||
new ParseField("page_timeout"));
|
||||
parser.declareObject(AbstractSqlQueryRequest::filter,
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), new ParseField("filter"));
|
||||
|
@ -185,7 +181,7 @@ public abstract class AbstractSqlQueryRequest extends AbstractSqlRequest impleme
|
|||
public AbstractSqlQueryRequest(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
query = in.readString();
|
||||
params = in.readList(SqlTypedParamValue::new);
|
||||
params = in.readList(AbstractSqlQueryRequest::readSqlTypedParamValue);
|
||||
timeZone = TimeZone.getTimeZone(in.readString());
|
||||
fetchSize = in.readVInt();
|
||||
requestTimeout = in.readTimeValue();
|
||||
|
@ -193,11 +189,23 @@ public abstract class AbstractSqlQueryRequest extends AbstractSqlRequest impleme
|
|||
filter = in.readOptionalNamedWriteable(QueryBuilder.class);
|
||||
}
|
||||
|
||||
public static void writeSqlTypedParamValue(StreamOutput out, SqlTypedParamValue value) throws IOException {
|
||||
out.writeEnum(value.dataType);
|
||||
out.writeGenericValue(value.value);
|
||||
}
|
||||
|
||||
public static SqlTypedParamValue readSqlTypedParamValue(StreamInput in) throws IOException {
|
||||
return new SqlTypedParamValue(in.readEnum(DataType.class), in.readGenericValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeString(query);
|
||||
out.writeList(params);
|
||||
out.writeVInt(params.size());
|
||||
for (SqlTypedParamValue param: params) {
|
||||
writeSqlTypedParamValue(out, param);
|
||||
}
|
||||
out.writeString(timeZone.getID());
|
||||
out.writeVInt(fetchSize);
|
||||
out.writeTimeValue(requestTimeout);
|
||||
|
@ -224,36 +232,4 @@ public abstract class AbstractSqlQueryRequest extends AbstractSqlRequest impleme
|
|||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), query, timeZone, fetchSize, requestTimeout, pageTimeout, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
if (query != null) {
|
||||
builder.field("query", query);
|
||||
}
|
||||
if (this.params.isEmpty() == false) {
|
||||
builder.startArray("params");
|
||||
for (SqlTypedParamValue val : this.params) {
|
||||
val.toXContent(builder, params);
|
||||
}
|
||||
builder.endArray();
|
||||
}
|
||||
if (timeZone != null) {
|
||||
builder.field("time_zone", timeZone.getID());
|
||||
}
|
||||
if (fetchSize != DEFAULT_FETCH_SIZE) {
|
||||
builder.field("fetch_size", fetchSize);
|
||||
}
|
||||
if (requestTimeout != DEFAULT_REQUEST_TIMEOUT) {
|
||||
builder.field("request_timeout", requestTimeout.getStringRep());
|
||||
}
|
||||
if (pageTimeout != DEFAULT_PAGE_TIMEOUT) {
|
||||
builder.field("page_timeout", pageTimeout.getStringRep());
|
||||
}
|
||||
if (filter != null) {
|
||||
builder.field("filter");
|
||||
filter.toXContent(builder, params);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import org.elasticsearch.action.ActionRequestValidationException;
|
|||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
|
@ -24,24 +24,6 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
|
|||
*/
|
||||
public abstract class AbstractSqlRequest extends ActionRequest implements ToXContent {
|
||||
|
||||
public enum Mode {
|
||||
PLAIN,
|
||||
JDBC;
|
||||
|
||||
public static Mode fromString(String mode) {
|
||||
if (mode == null) {
|
||||
return PLAIN;
|
||||
}
|
||||
return Mode.valueOf(mode.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
private Mode mode = Mode.PLAIN;
|
||||
|
||||
protected AbstractSqlRequest() {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.sql.plugin;
|
|||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
@ -28,19 +29,19 @@ public class CliFormatter implements Writeable {
|
|||
|
||||
/**
|
||||
* Create a new {@linkplain CliFormatter} for formatting responses similar
|
||||
* to the provided {@link SqlQueryResponse}.
|
||||
* to the provided columns and rows.
|
||||
*/
|
||||
public CliFormatter(SqlQueryResponse response) {
|
||||
public CliFormatter(List<ColumnInfo> columns, List<List<Object>> rows) {
|
||||
// Figure out the column widths:
|
||||
// 1. Start with the widths of the column names
|
||||
width = new int[response.columns().size()];
|
||||
width = new int[columns.size()];
|
||||
for (int i = 0; i < width.length; i++) {
|
||||
// TODO read the width from the data type?
|
||||
width[i] = Math.max(MIN_COLUMN_WIDTH, response.columns().get(i).name().length());
|
||||
width[i] = Math.max(MIN_COLUMN_WIDTH, columns.get(i).name().length());
|
||||
}
|
||||
|
||||
// 2. Expand columns to fit the largest value
|
||||
for (List<Object> row : response.rows()) {
|
||||
for (List<Object> row : rows) {
|
||||
for (int i = 0; i < width.length; i++) {
|
||||
// TODO are we sure toString is correct here? What about dates that come back as longs.
|
||||
// Tracked by https://github.com/elastic/x-pack-elasticsearch/issues/3081
|
||||
|
@ -62,15 +63,15 @@ public class CliFormatter implements Writeable {
|
|||
* Format the provided {@linkplain SqlQueryResponse} for the CLI
|
||||
* including the header lines.
|
||||
*/
|
||||
public String formatWithHeader(SqlQueryResponse response) {
|
||||
public String formatWithHeader(List<ColumnInfo> columns, List<List<Object>> rows) {
|
||||
// The header lines
|
||||
StringBuilder sb = new StringBuilder(estimateSize(response.rows().size() + 2));
|
||||
StringBuilder sb = new StringBuilder(estimateSize(rows.size() + 2));
|
||||
for (int i = 0; i < width.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append('|');
|
||||
}
|
||||
|
||||
String name = response.columns().get(i).name();
|
||||
String name = columns.get(i).name();
|
||||
// left padding
|
||||
int leftPadding = (width[i] - name.length()) / 2;
|
||||
for (int j = 0; j < leftPadding; j++) {
|
||||
|
@ -98,19 +99,19 @@ public class CliFormatter implements Writeable {
|
|||
/* Now format the results. Sadly, this means that column
|
||||
* widths are entirely determined by the first batch of
|
||||
* results. */
|
||||
return formatWithoutHeader(sb, response);
|
||||
return formatWithoutHeader(sb, rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the provided {@linkplain SqlQueryResponse} for the CLI
|
||||
* without the header lines.
|
||||
*/
|
||||
public String formatWithoutHeader(SqlQueryResponse response) {
|
||||
return formatWithoutHeader(new StringBuilder(estimateSize(response.rows().size())), response);
|
||||
public String formatWithoutHeader(List<List<Object>> rows) {
|
||||
return formatWithoutHeader(new StringBuilder(estimateSize(rows.size())), rows);
|
||||
}
|
||||
|
||||
private String formatWithoutHeader(StringBuilder sb, SqlQueryResponse response) {
|
||||
for (List<Object> row : response.rows()) {
|
||||
private String formatWithoutHeader(StringBuilder sb, List<List<Object>> rows) {
|
||||
for (List<Object> row : rows) {
|
||||
for (int i = 0; i < width.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append('|');
|
||||
|
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* 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.plugin;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.JDBCType;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
|
||||
/**
|
||||
* Information about a column returned by the listColumns response
|
||||
*/
|
||||
public class MetaColumnInfo implements Writeable, ToXContentObject {
|
||||
|
||||
private static final ConstructingObjectParser<MetaColumnInfo, Void> PARSER =
|
||||
new ConstructingObjectParser<>("column_info", true, objects ->
|
||||
new MetaColumnInfo(
|
||||
(String) objects[0],
|
||||
(String) objects[1],
|
||||
(String) objects[2],
|
||||
objects[3] == null ? null : JDBCType.valueOf((int) objects[3]),
|
||||
objects[4] == null ? 0 : (int) objects[4],
|
||||
(int) objects[5]));
|
||||
|
||||
private static final ParseField TABLE = new ParseField("table");
|
||||
private static final ParseField NAME = new ParseField("name");
|
||||
private static final ParseField ES_TYPE = new ParseField("type");
|
||||
private static final ParseField JDBC_TYPE = new ParseField("jdbc_type");
|
||||
private static final ParseField SIZE = new ParseField("size");
|
||||
private static final ParseField POSITION = new ParseField("position");
|
||||
|
||||
static {
|
||||
PARSER.declareString(constructorArg(), TABLE);
|
||||
PARSER.declareString(constructorArg(), NAME);
|
||||
PARSER.declareString(constructorArg(), ES_TYPE);
|
||||
PARSER.declareInt(optionalConstructorArg(), JDBC_TYPE);
|
||||
PARSER.declareInt(optionalConstructorArg(), SIZE);
|
||||
PARSER.declareInt(constructorArg(), POSITION);
|
||||
}
|
||||
|
||||
private final String table;
|
||||
private final String name;
|
||||
private final String esType;
|
||||
@Nullable
|
||||
private final JDBCType jdbcType;
|
||||
private final int size;
|
||||
private final int position;
|
||||
|
||||
public MetaColumnInfo(String table, String name, String esType, JDBCType jdbcType, int size, int position) {
|
||||
this.table = table;
|
||||
this.name = name;
|
||||
this.esType = esType;
|
||||
this.jdbcType = jdbcType;
|
||||
this.size = size;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public MetaColumnInfo(String table, String name, String esType, int position) {
|
||||
this(table, name, esType, null, 0, position);
|
||||
}
|
||||
|
||||
MetaColumnInfo(StreamInput in) throws IOException {
|
||||
table = in.readString();
|
||||
name = in.readString();
|
||||
esType = in.readString();
|
||||
if (in.readBoolean()) {
|
||||
jdbcType = JDBCType.valueOf(in.readVInt());
|
||||
size = in.readVInt();
|
||||
} else {
|
||||
jdbcType = null;
|
||||
size = 0;
|
||||
}
|
||||
position = in.readVInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(table);
|
||||
out.writeString(name);
|
||||
out.writeString(esType);
|
||||
if (jdbcType != null) {
|
||||
out.writeBoolean(true);
|
||||
out.writeVInt(jdbcType.getVendorTypeNumber());
|
||||
out.writeVInt(size);
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
out.writeVInt(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field("table", table);
|
||||
builder.field("name", name);
|
||||
builder.field("type", esType);
|
||||
if (jdbcType != null) {
|
||||
builder.field("jdbc_type", jdbcType.getVendorTypeNumber());
|
||||
builder.field("size", size);
|
||||
}
|
||||
builder.field("position", position);
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
|
||||
public static MetaColumnInfo fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the table.
|
||||
*/
|
||||
public String table() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the column.
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the column in Elasticsearch.
|
||||
*/
|
||||
public String esType() {
|
||||
return esType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the column as it would be returned by a JDBC driver.
|
||||
*/
|
||||
public JDBCType jdbcType() {
|
||||
return jdbcType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Precision
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Column position with in the tables
|
||||
*/
|
||||
public int position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Strings.toString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
MetaColumnInfo that = (MetaColumnInfo) o;
|
||||
return size == that.size &&
|
||||
position == that.position &&
|
||||
Objects.equals(table, that.table) &&
|
||||
Objects.equals(name, that.name) &&
|
||||
Objects.equals(esType, that.esType) &&
|
||||
jdbcType == that.jdbcType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(table, name, esType, jdbcType, size, position);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,6 @@ public class SqlClearCursorAction
|
|||
|
||||
public static final SqlClearCursorAction INSTANCE = new SqlClearCursorAction();
|
||||
public static final String NAME = "indices:data/read/sql/close_cursor";
|
||||
public static final String REST_ENDPOINT = "/_xpack/sql/close";
|
||||
|
||||
private SqlClearCursorAction() {
|
||||
super(NAME);
|
||||
|
|
|
@ -10,9 +10,9 @@ 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;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
@ -23,13 +23,13 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constru
|
|||
/**
|
||||
* Request to clean all SQL resources associated with the cursor
|
||||
*/
|
||||
public class SqlClearCursorRequest extends AbstractSqlRequest implements ToXContentObject {
|
||||
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]
|
||||
));
|
||||
new ConstructingObjectParser<>(SqlClearCursorAction.NAME, true, (objects, mode) -> new SqlClearCursorRequest(
|
||||
mode,
|
||||
(String) objects[0]
|
||||
));
|
||||
|
||||
static {
|
||||
PARSER.declareString(constructorArg(), new ParseField("cursor"));
|
||||
|
@ -96,10 +96,8 @@ public class SqlClearCursorRequest extends AbstractSqlRequest implements ToXCont
|
|||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field("cursor", cursor);
|
||||
builder.endObject();
|
||||
return builder;
|
||||
// This is needed just to test round-trip compatibility with proto.SqlClearCursorRequest
|
||||
return new org.elasticsearch.xpack.sql.proto.SqlClearCursorRequest(mode(), cursor).toXContent(builder, params);
|
||||
}
|
||||
|
||||
public static SqlClearCursorRequest fromXContent(XContentParser parser, Mode mode) {
|
||||
|
|
|
@ -6,13 +6,10 @@
|
|||
package org.elasticsearch.xpack.sql.plugin;
|
||||
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -20,20 +17,13 @@ import java.util.Objects;
|
|||
|
||||
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
|
||||
import static org.elasticsearch.rest.RestStatus.OK;
|
||||
import static org.elasticsearch.xpack.sql.proto.SqlClearCursorResponse.SUCCEEDED;
|
||||
|
||||
/**
|
||||
* Response to the request to clean all SQL resources associated with the cursor
|
||||
*/
|
||||
public class SqlClearCursorResponse extends ActionResponse implements StatusToXContentObject {
|
||||
|
||||
private static final ParseField SUCCEEDED = new ParseField("succeeded");
|
||||
public static final ObjectParser<SqlClearCursorResponse, Void> PARSER =
|
||||
new ObjectParser<>(SqlClearCursorAction.NAME, true, SqlClearCursorResponse::new);
|
||||
static {
|
||||
PARSER.declareBoolean(SqlClearCursorResponse::setSucceeded, SUCCEEDED);
|
||||
}
|
||||
|
||||
|
||||
private boolean succeeded;
|
||||
|
||||
public SqlClearCursorResponse(boolean succeeded) {
|
||||
|
@ -93,9 +83,4 @@ public class SqlClearCursorResponse extends ActionResponse implements StatusToXC
|
|||
return Objects.hash(succeeded);
|
||||
}
|
||||
|
||||
public static SqlClearCursorResponse fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ public class SqlQueryAction extends Action<SqlQueryRequest, SqlQueryResponse, Sq
|
|||
|
||||
public static final SqlQueryAction INSTANCE = new SqlQueryAction();
|
||||
public static final String NAME = "indices:data/read/sql";
|
||||
public static final String REST_ENDPOINT = "/_xpack/sql";
|
||||
|
||||
private SqlQueryAction() {
|
||||
super(NAME);
|
||||
|
|
|
@ -12,11 +12,12 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
|||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
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.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
@ -28,7 +29,7 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
|
|||
/**
|
||||
* Request to perform an sql query
|
||||
*/
|
||||
public class SqlQueryRequest extends AbstractSqlQueryRequest implements ToXContentObject {
|
||||
public class SqlQueryRequest extends AbstractSqlQueryRequest {
|
||||
private static final ObjectParser<SqlQueryRequest, Void> PARSER = objectParser(SqlQueryRequest::new);
|
||||
|
||||
public static final ParseField CURSOR = new ParseField("cursor");
|
||||
|
@ -37,7 +38,7 @@ public class SqlQueryRequest extends AbstractSqlQueryRequest implements ToXConte
|
|||
static {
|
||||
PARSER.declareString(SqlQueryRequest::cursor, CURSOR);
|
||||
PARSER.declareObject(SqlQueryRequest::filter,
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), FILTER);
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), FILTER);
|
||||
}
|
||||
|
||||
private String cursor = "";
|
||||
|
@ -108,22 +109,13 @@ public class SqlQueryRequest extends AbstractSqlQueryRequest implements ToXConte
|
|||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
super.toXContent(builder, params);
|
||||
if (cursor != null) {
|
||||
builder.field("cursor", cursor);
|
||||
}
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragment() {
|
||||
return false;
|
||||
// This is needed just to test round-trip compatibility with proto.SqlQueryRequest
|
||||
return new org.elasticsearch.xpack.sql.proto.SqlQueryRequest(mode(), query(), params(), timeZone(), fetchSize(),
|
||||
requestTimeout(), pageTimeout(), filter(), cursor()).toXContent(builder, params);
|
||||
}
|
||||
|
||||
public static SqlQueryRequest fromXContent(XContentParser parser, Mode mode) {
|
||||
SqlQueryRequest request = PARSER.apply(parser, null);
|
||||
SqlQueryRequest request = PARSER.apply(parser, null);
|
||||
request.mode(mode);
|
||||
return request;
|
||||
}
|
||||
|
|
|
@ -9,25 +9,22 @@ import org.elasticsearch.action.ActionRequestBuilder;
|
|||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlRequest.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_FETCH_SIZE;
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_PAGE_TIMEOUT;
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_REQUEST_TIMEOUT;
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_TIME_ZONE;
|
||||
|
||||
/**
|
||||
* The builder to build sql request
|
||||
*/
|
||||
public class SqlQueryRequestBuilder extends ActionRequestBuilder<SqlQueryRequest, SqlQueryResponse, SqlQueryRequestBuilder> {
|
||||
|
||||
public SqlQueryRequestBuilder(ElasticsearchClient client, SqlQueryAction action) {
|
||||
this(client, action, "", Collections.emptyList(), null, DEFAULT_TIME_ZONE, DEFAULT_FETCH_SIZE, DEFAULT_REQUEST_TIMEOUT,
|
||||
DEFAULT_PAGE_TIMEOUT, "", Mode.PLAIN);
|
||||
this(client, action, "", Collections.emptyList(), null, Protocol.TIME_ZONE, Protocol.FETCH_SIZE, Protocol.REQUEST_TIMEOUT,
|
||||
Protocol.PAGE_TIMEOUT, "", Mode.PLAIN);
|
||||
}
|
||||
|
||||
public SqlQueryRequestBuilder(ElasticsearchClient client, SqlQueryAction action, String query, List<SqlTypedParamValue> params,
|
||||
|
|
|
@ -7,49 +7,28 @@ package org.elasticsearch.xpack.sql.plugin;
|
|||
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.joda.time.ReadableDateTime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.JDBCType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.parseFieldsValue;
|
||||
|
||||
/**
|
||||
* Response to perform an sql query
|
||||
*/
|
||||
public class SqlQueryResponse extends ActionResponse implements ToXContentObject {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static final ConstructingObjectParser<SqlQueryResponse, Void> PARSER = new ConstructingObjectParser<>("sql", true,
|
||||
objects -> new SqlQueryResponse(
|
||||
objects[0] == null ? "" : (String) objects[0],
|
||||
(List<ColumnInfo>) objects[1],
|
||||
(List<List<Object>>) objects[2]));
|
||||
|
||||
public static final ParseField CURSOR = new ParseField("cursor");
|
||||
public static final ParseField COLUMNS = new ParseField("columns");
|
||||
public static final ParseField ROWS = new ParseField("rows");
|
||||
|
||||
static {
|
||||
PARSER.declareString(optionalConstructorArg(), CURSOR);
|
||||
PARSER.declareObjectArray(optionalConstructorArg(), (p, c) -> ColumnInfo.fromXContent(p), COLUMNS);
|
||||
PARSER.declareField(constructorArg(), (p, c) -> parseRows(p), ROWS, ValueType.OBJECT_ARRAY);
|
||||
}
|
||||
|
||||
// TODO: Simplify cursor handling
|
||||
private String cursor;
|
||||
private List<ColumnInfo> columns;
|
||||
|
@ -109,7 +88,7 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
int columnCount = in.readVInt();
|
||||
List<ColumnInfo> columns = new ArrayList<>(columnCount);
|
||||
for (int c = 0; c < columnCount; c++) {
|
||||
columns.add(new ColumnInfo(in));
|
||||
columns.add(readColumnInfo(in));
|
||||
}
|
||||
this.columns = unmodifiableList(columns);
|
||||
} else {
|
||||
|
@ -139,7 +118,7 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
out.writeBoolean(true);
|
||||
out.writeVInt(columns.size());
|
||||
for (ColumnInfo column : columns) {
|
||||
column.writeTo(out);
|
||||
writeColumnInfo(out, column);
|
||||
}
|
||||
}
|
||||
out.writeVInt(rows.size());
|
||||
|
@ -155,7 +134,7 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
AbstractSqlRequest.Mode mode = AbstractSqlRequest.Mode.fromString(params.param("mode"));
|
||||
Mode mode = Mode.fromString(params.param("mode"));
|
||||
builder.startObject();
|
||||
{
|
||||
if (columns != null) {
|
||||
|
@ -187,8 +166,8 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
/**
|
||||
* Serializes the provided value in SQL-compatible way based on the client mode
|
||||
*/
|
||||
public static XContentBuilder value(XContentBuilder builder, AbstractSqlRequest.Mode mode, Object value) throws IOException {
|
||||
if (mode == AbstractSqlRequest.Mode.JDBC && value instanceof ReadableDateTime) {
|
||||
public static XContentBuilder value(XContentBuilder builder, Mode mode, Object value) throws IOException {
|
||||
if (mode == Mode.JDBC && value instanceof ReadableDateTime) {
|
||||
// JDBC cannot parse dates in string format
|
||||
builder.value(((ReadableDateTime) value).getMillis());
|
||||
} else {
|
||||
|
@ -197,34 +176,33 @@ public class SqlQueryResponse extends ActionResponse implements ToXContentObject
|
|||
return builder;
|
||||
}
|
||||
|
||||
public static SqlQueryResponse fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
public static ColumnInfo readColumnInfo(StreamInput in) throws IOException {
|
||||
String table = in.readString();
|
||||
String name = in.readString();
|
||||
String esType = in.readString();
|
||||
JDBCType jdbcType;
|
||||
int displaySize;
|
||||
if (in.readBoolean()) {
|
||||
jdbcType = JDBCType.valueOf(in.readVInt());
|
||||
displaySize = in.readVInt();
|
||||
} else {
|
||||
jdbcType = null;
|
||||
displaySize = 0;
|
||||
}
|
||||
return new ColumnInfo(table, name, esType, jdbcType, displaySize);
|
||||
}
|
||||
|
||||
public static List<List<Object>> parseRows(XContentParser parser) throws IOException {
|
||||
List<List<Object>> list = new ArrayList<>();
|
||||
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||
if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
|
||||
list.add(parseRow(parser));
|
||||
} else {
|
||||
throw new IllegalStateException("expected start array but got [" + parser.currentToken() + "]");
|
||||
}
|
||||
public static void writeColumnInfo(StreamOutput out, ColumnInfo columnInfo) throws IOException {
|
||||
out.writeString(columnInfo.table());
|
||||
out.writeString(columnInfo.name());
|
||||
out.writeString(columnInfo.esType());
|
||||
if (columnInfo.jdbcType() != null) {
|
||||
out.writeBoolean(true);
|
||||
out.writeVInt(columnInfo.jdbcType().getVendorTypeNumber());
|
||||
out.writeVInt(columnInfo.displaySize());
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Object> parseRow(XContentParser parser) throws IOException {
|
||||
List<Object> list = new ArrayList<>();
|
||||
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||
if (parser.currentToken().isValue()) {
|
||||
list.add(parseFieldsValue(parser));
|
||||
} else if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
|
||||
list.add(null);
|
||||
} else {
|
||||
throw new IllegalStateException("expected value but got [" + parser.currentToken() + "]");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,8 +10,11 @@ import org.elasticsearch.common.Strings;
|
|||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
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.QueryBuilder;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
@ -56,4 +59,14 @@ public class SqlTranslateRequest extends AbstractSqlQueryRequest {
|
|||
request.mode(mode);
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
// This is needed just to test parsing of SqlTranslateRequest, so we can reuse SqlQuerySerialization
|
||||
return new org.elasticsearch.xpack.sql.proto.SqlQueryRequest(mode(), query(), params(), timeZone(), fetchSize(),
|
||||
requestTimeout(), pageTimeout(), filter(), null).toXContent(builder, params);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -9,27 +9,25 @@ import org.elasticsearch.action.ActionRequestBuilder;
|
|||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
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.SqlTypedParamValue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_FETCH_SIZE;
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_PAGE_TIMEOUT;
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_REQUEST_TIMEOUT;
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest.DEFAULT_TIME_ZONE;
|
||||
|
||||
/**
|
||||
* Builder for the request for the sql action for translating SQL queries into ES requests
|
||||
*/
|
||||
public class SqlTranslateRequestBuilder extends ActionRequestBuilder<SqlTranslateRequest, SqlTranslateResponse,
|
||||
SqlTranslateRequestBuilder> {
|
||||
public SqlTranslateRequestBuilder(ElasticsearchClient client, SqlTranslateAction action) {
|
||||
this(client, action, AbstractSqlRequest.Mode.PLAIN, null, null, Collections.emptyList(), DEFAULT_TIME_ZONE, DEFAULT_FETCH_SIZE,
|
||||
DEFAULT_REQUEST_TIMEOUT, DEFAULT_PAGE_TIMEOUT);
|
||||
this(client, action, Mode.PLAIN, null, null, Collections.emptyList(), Protocol.TIME_ZONE, Protocol.FETCH_SIZE,
|
||||
Protocol.REQUEST_TIMEOUT, Protocol.PAGE_TIMEOUT);
|
||||
}
|
||||
|
||||
public SqlTranslateRequestBuilder(ElasticsearchClient client, SqlTranslateAction action, AbstractSqlRequest.Mode mode, String query,
|
||||
public SqlTranslateRequestBuilder(ElasticsearchClient client, SqlTranslateAction action, Mode mode, String query,
|
||||
QueryBuilder filter, List<SqlTypedParamValue> params, TimeZone timeZone, int fetchSize,
|
||||
TimeValue requestTimeout, TimeValue pageTimeout) {
|
||||
super(client, action, new SqlTranslateRequest(mode, query, params, filter, timeZone, fetchSize, requestTimeout, pageTimeout));
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import org.elasticsearch.common.xcontent.ToXContentFragment;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Base request for all SQL-related requests for JDBC/CLI client
|
||||
* <p>
|
||||
* Contains information about the client mode that can be used to generate different responses based on the caller type.
|
||||
*/
|
||||
public abstract class AbstractSqlRequest implements ToXContentFragment {
|
||||
|
||||
private final Mode mode;
|
||||
|
||||
protected AbstractSqlRequest(Mode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public Mode mode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AbstractSqlRequest that = (AbstractSqlRequest) o;
|
||||
return mode == that.mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mode);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,14 +3,11 @@
|
|||
* 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.plugin;
|
||||
package org.elasticsearch.xpack.sql.proto;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -26,16 +23,16 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optiona
|
|||
/**
|
||||
* Information about a column returned with first query response
|
||||
*/
|
||||
public final class ColumnInfo implements Writeable, ToXContentObject {
|
||||
public class ColumnInfo implements ToXContentObject {
|
||||
|
||||
private static final ConstructingObjectParser<ColumnInfo, Void> PARSER =
|
||||
new ConstructingObjectParser<>("column_info", true, objects ->
|
||||
new ColumnInfo(
|
||||
objects[0] == null ? "" : (String) objects[0],
|
||||
(String) objects[1],
|
||||
(String) objects[2],
|
||||
objects[3] == null ? null : JDBCType.valueOf((int) objects[3]),
|
||||
objects[4] == null ? 0 : (int) objects[4]));
|
||||
new ConstructingObjectParser<>("column_info", true, objects ->
|
||||
new ColumnInfo(
|
||||
objects[0] == null ? "" : (String) objects[0],
|
||||
(String) objects[1],
|
||||
(String) objects[2],
|
||||
objects[3] == null ? null : JDBCType.valueOf((int) objects[3]),
|
||||
objects[4] == null ? 0 : (int) objects[4]));
|
||||
|
||||
private static final ParseField TABLE = new ParseField("table");
|
||||
private static final ParseField NAME = new ParseField("name");
|
||||
|
@ -74,33 +71,6 @@ public final class ColumnInfo implements Writeable, ToXContentObject {
|
|||
this.displaySize = 0;
|
||||
}
|
||||
|
||||
ColumnInfo(StreamInput in) throws IOException {
|
||||
table = in.readString();
|
||||
name = in.readString();
|
||||
esType = in.readString();
|
||||
if (in.readBoolean()) {
|
||||
jdbcType = JDBCType.valueOf(in.readVInt());
|
||||
displaySize = in.readVInt();
|
||||
} else {
|
||||
jdbcType = null;
|
||||
displaySize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(table);
|
||||
out.writeString(name);
|
||||
out.writeString(esType);
|
||||
if (jdbcType != null) {
|
||||
out.writeBoolean(true);
|
||||
out.writeVInt(jdbcType.getVendorTypeNumber());
|
||||
out.writeVInt(displaySize);
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
@ -162,10 +132,10 @@ public final class ColumnInfo implements Writeable, ToXContentObject {
|
|||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ColumnInfo that = (ColumnInfo) o;
|
||||
return displaySize == that.displaySize &&
|
||||
Objects.equals(table, that.table) &&
|
||||
Objects.equals(name, that.name) &&
|
||||
Objects.equals(esType, that.esType) &&
|
||||
jdbcType == that.jdbcType;
|
||||
Objects.equals(table, that.table) &&
|
||||
Objects.equals(name, that.name) &&
|
||||
Objects.equals(esType, that.esType) &&
|
||||
jdbcType == that.jdbcType;
|
||||
}
|
||||
|
||||
@Override
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Main (/) response for JDBC/CLI client
|
||||
*/
|
||||
public class MainResponse {
|
||||
private String nodeName;
|
||||
// TODO: Add parser for Version
|
||||
private Version version;
|
||||
private String clusterName;
|
||||
private String clusterUuid;
|
||||
// TODO: Add parser for Build
|
||||
private Build build;
|
||||
|
||||
private MainResponse() {
|
||||
}
|
||||
|
||||
public MainResponse(String nodeName, Version version, String clusterName, String clusterUuid, Build build) {
|
||||
this.nodeName = nodeName;
|
||||
this.version = version;
|
||||
this.clusterName = clusterName;
|
||||
this.clusterUuid = clusterUuid;
|
||||
this.build = build;
|
||||
}
|
||||
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getClusterName() {
|
||||
return clusterName;
|
||||
}
|
||||
|
||||
public String getClusterUuid() {
|
||||
return clusterUuid;
|
||||
}
|
||||
|
||||
public Build getBuild() {
|
||||
return build;
|
||||
}
|
||||
|
||||
private static final ObjectParser<MainResponse, Void> PARSER = new ObjectParser<>(MainResponse.class.getName(), true,
|
||||
MainResponse::new);
|
||||
|
||||
static {
|
||||
PARSER.declareString((response, value) -> response.nodeName = value, new ParseField("name"));
|
||||
PARSER.declareString((response, value) -> response.clusterName = value, new ParseField("cluster_name"));
|
||||
PARSER.declareString((response, value) -> response.clusterUuid = value, new ParseField("cluster_uuid"));
|
||||
PARSER.declareString((response, value) -> {
|
||||
}, new ParseField("tagline"));
|
||||
PARSER.declareObject((response, value) -> {
|
||||
final String buildFlavor = (String) value.get("build_flavor");
|
||||
final String buildType = (String) value.get("build_type");
|
||||
response.build =
|
||||
new Build(
|
||||
buildFlavor == null ? Build.Flavor.UNKNOWN : Build.Flavor.fromDisplayName(buildFlavor),
|
||||
buildType == null ? Build.Type.UNKNOWN : Build.Type.fromDisplayName(buildType),
|
||||
(String) value.get("build_hash"),
|
||||
(String) value.get("build_date"),
|
||||
(boolean) value.get("build_snapshot"));
|
||||
response.version = Version.fromString((String) value.get("number"));
|
||||
}, (parser, context) -> parser.map(), new ParseField("version"));
|
||||
}
|
||||
|
||||
public static MainResponse fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MainResponse other = (MainResponse) o;
|
||||
return Objects.equals(nodeName, other.nodeName) &&
|
||||
Objects.equals(version, other.version) &&
|
||||
Objects.equals(clusterUuid, other.clusterUuid) &&
|
||||
Objects.equals(build, other.build) &&
|
||||
Objects.equals(clusterName, other.clusterName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(nodeName, version, clusterUuid, build, clusterName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* SQL protocol mode
|
||||
*/
|
||||
public enum Mode {
|
||||
PLAIN,
|
||||
JDBC;
|
||||
|
||||
public static Mode fromString(String mode) {
|
||||
if (mode == null) {
|
||||
return PLAIN;
|
||||
}
|
||||
return Mode.valueOf(mode.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Sql protocol defaults and end-points shared between JDBC and REST protocol implementations
|
||||
*/
|
||||
public final class Protocol {
|
||||
public static final TimeZone TIME_ZONE = TimeZone.getTimeZone("UTC");
|
||||
|
||||
/**
|
||||
* Global choice for the default fetch size.
|
||||
*/
|
||||
public static final int FETCH_SIZE = 1000;
|
||||
public static final TimeValue REQUEST_TIMEOUT = TimeValue.timeValueSeconds(90);
|
||||
public static final TimeValue PAGE_TIMEOUT = TimeValue.timeValueSeconds(45);
|
||||
|
||||
/**
|
||||
* SQL-related endpoints
|
||||
*/
|
||||
public static final String CLEAR_CURSOR_REST_ENDPOINT = "/_xpack/sql/close";
|
||||
public static final String SQL_QUERY_REST_ENDPOINT = "/_xpack/sql";
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Request to clean all SQL resources associated with the cursor for JDBC/CLI client
|
||||
*/
|
||||
public class SqlClearCursorRequest extends AbstractSqlRequest {
|
||||
|
||||
private final String cursor;
|
||||
|
||||
public SqlClearCursorRequest(Mode mode, String cursor) {
|
||||
super(mode);
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
public String getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
SqlClearCursorRequest that = (SqlClearCursorRequest) o;
|
||||
return Objects.equals(cursor, that.cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.field("cursor", cursor);
|
||||
return builder;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
|
||||
/**
|
||||
* Response to the request to clean all SQL resources associated with the cursor for JDBC/CLI client
|
||||
*/
|
||||
public class SqlClearCursorResponse {
|
||||
|
||||
public static final ParseField SUCCEEDED = new ParseField("succeeded");
|
||||
public static final ConstructingObjectParser<SqlClearCursorResponse, Void> PARSER =
|
||||
new ConstructingObjectParser<>(SqlClearCursorResponse.class.getName(), true,
|
||||
objects -> new SqlClearCursorResponse(objects[0] == null ? false : (boolean) objects[0]));
|
||||
|
||||
static {
|
||||
PARSER.declareBoolean(optionalConstructorArg(), SUCCEEDED);
|
||||
}
|
||||
|
||||
|
||||
private final boolean succeeded;
|
||||
|
||||
public SqlClearCursorResponse(boolean succeeded) {
|
||||
this.succeeded = succeeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the attempt to clear a cursor was successful.
|
||||
*/
|
||||
public boolean isSucceeded() {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SqlClearCursorResponse response = (SqlClearCursorResponse) o;
|
||||
return succeeded == response.succeeded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(succeeded);
|
||||
}
|
||||
|
||||
public static SqlClearCursorResponse fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Sql query request for JDBC/CLI client
|
||||
*/
|
||||
public class SqlQueryRequest extends AbstractSqlRequest {
|
||||
@Nullable
|
||||
private final String cursor;
|
||||
private final String query;
|
||||
private final TimeZone timeZone;
|
||||
private final int fetchSize;
|
||||
private final TimeValue requestTimeout;
|
||||
private final TimeValue pageTimeout;
|
||||
@Nullable
|
||||
private final ToXContent filter;
|
||||
private final List<SqlTypedParamValue> params;
|
||||
|
||||
|
||||
public SqlQueryRequest(Mode mode, String query, List<SqlTypedParamValue> params, TimeZone timeZone,
|
||||
int fetchSize, TimeValue requestTimeout, TimeValue pageTimeout, ToXContent filter, String cursor) {
|
||||
super(mode);
|
||||
this.query = query;
|
||||
this.params = params;
|
||||
this.timeZone = timeZone;
|
||||
this.fetchSize = fetchSize;
|
||||
this.requestTimeout = requestTimeout;
|
||||
this.pageTimeout = pageTimeout;
|
||||
this.filter = filter;
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
public SqlQueryRequest(Mode mode, String query, List<SqlTypedParamValue> params, ToXContent filter, TimeZone timeZone,
|
||||
int fetchSize, TimeValue requestTimeout, TimeValue pageTimeout) {
|
||||
this(mode, query, params, timeZone, fetchSize, requestTimeout, pageTimeout, filter, null);
|
||||
}
|
||||
|
||||
public SqlQueryRequest(Mode mode, String cursor, TimeValue requestTimeout, TimeValue pageTimeout) {
|
||||
this(mode, "", Collections.emptyList(), Protocol.TIME_ZONE, Protocol.FETCH_SIZE, requestTimeout, pageTimeout, null, cursor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The key that must be sent back to SQL to access the next page of
|
||||
* results.
|
||||
*/
|
||||
public String cursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text of SQL query
|
||||
*/
|
||||
public String query() {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional list of parameters if the SQL query is parametrized
|
||||
*/
|
||||
public List<SqlTypedParamValue> params() {
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* The client's time zone
|
||||
*/
|
||||
public TimeZone timeZone() {
|
||||
return timeZone;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hint about how many results to fetch at once.
|
||||
*/
|
||||
public int fetchSize() {
|
||||
return fetchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* The timeout specified on the search request
|
||||
*/
|
||||
public TimeValue requestTimeout() {
|
||||
return requestTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* The scroll timeout
|
||||
*/
|
||||
public TimeValue pageTimeout() {
|
||||
return pageTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional Query DSL defined query that can added as a filter on the top of the SQL query
|
||||
*/
|
||||
public ToXContent filter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
SqlQueryRequest that = (SqlQueryRequest) o;
|
||||
return fetchSize == that.fetchSize &&
|
||||
Objects.equals(query, that.query) &&
|
||||
Objects.equals(params, that.params) &&
|
||||
Objects.equals(timeZone, that.timeZone) &&
|
||||
Objects.equals(requestTimeout, that.requestTimeout) &&
|
||||
Objects.equals(pageTimeout, that.pageTimeout) &&
|
||||
Objects.equals(filter, that.filter) &&
|
||||
Objects.equals(cursor, that.cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), query, timeZone, fetchSize, requestTimeout, pageTimeout, filter, cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
if (query != null) {
|
||||
builder.field("query", query);
|
||||
}
|
||||
if (this.params.isEmpty() == false) {
|
||||
builder.startArray("params");
|
||||
for (SqlTypedParamValue val : this.params) {
|
||||
val.toXContent(builder, params);
|
||||
}
|
||||
builder.endArray();
|
||||
}
|
||||
if (timeZone != null) {
|
||||
builder.field("time_zone", timeZone.getID());
|
||||
}
|
||||
if (fetchSize != Protocol.FETCH_SIZE) {
|
||||
builder.field("fetch_size", fetchSize);
|
||||
}
|
||||
if (requestTimeout != Protocol.REQUEST_TIMEOUT) {
|
||||
builder.field("request_timeout", requestTimeout.getStringRep());
|
||||
}
|
||||
if (pageTimeout != Protocol.PAGE_TIMEOUT) {
|
||||
builder.field("page_timeout", pageTimeout.getStringRep());
|
||||
}
|
||||
if (filter != null) {
|
||||
builder.field("filter");
|
||||
filter.toXContent(builder, params);
|
||||
}
|
||||
if (cursor != null) {
|
||||
builder.field("cursor", cursor);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.proto;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.parseFieldsValue;
|
||||
|
||||
/**
|
||||
* Response to perform an sql query for JDBC/CLI client
|
||||
*/
|
||||
public class SqlQueryResponse {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static final ConstructingObjectParser<SqlQueryResponse, Void> PARSER = new ConstructingObjectParser<>("sql", true,
|
||||
objects -> new SqlQueryResponse(
|
||||
objects[0] == null ? "" : (String) objects[0],
|
||||
(List<ColumnInfo>) objects[1],
|
||||
(List<List<Object>>) objects[2]));
|
||||
|
||||
public static final ParseField CURSOR = new ParseField("cursor");
|
||||
public static final ParseField COLUMNS = new ParseField("columns");
|
||||
public static final ParseField ROWS = new ParseField("rows");
|
||||
|
||||
static {
|
||||
PARSER.declareString(optionalConstructorArg(), CURSOR);
|
||||
PARSER.declareObjectArray(optionalConstructorArg(), (p, c) -> ColumnInfo.fromXContent(p), COLUMNS);
|
||||
PARSER.declareField(constructorArg(), (p, c) -> parseRows(p), ROWS, ValueType.OBJECT_ARRAY);
|
||||
}
|
||||
|
||||
// TODO: Simplify cursor handling
|
||||
private final String cursor;
|
||||
private final List<ColumnInfo> columns;
|
||||
// TODO investigate reusing Page here - it probably is much more efficient
|
||||
private final List<List<Object>> rows;
|
||||
|
||||
public SqlQueryResponse(String cursor, @Nullable List<ColumnInfo> columns, List<List<Object>> rows) {
|
||||
this.cursor = cursor;
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* The key that must be sent back to SQL to access the next page of
|
||||
* results. If equal to "" then there is no next page.
|
||||
*/
|
||||
public String cursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return rows.size();
|
||||
}
|
||||
|
||||
public List<ColumnInfo> columns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public List<List<Object>> rows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public static SqlQueryResponse fromXContent(XContentParser parser) {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
||||
public static List<List<Object>> parseRows(XContentParser parser) throws IOException {
|
||||
List<List<Object>> list = new ArrayList<>();
|
||||
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||
if (parser.currentToken() == XContentParser.Token.START_ARRAY) {
|
||||
list.add(parseRow(parser));
|
||||
} else {
|
||||
throw new IllegalStateException("expected start array but got [" + parser.currentToken() + "]");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Object> parseRow(XContentParser parser) throws IOException {
|
||||
List<Object> list = new ArrayList<>();
|
||||
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||
if (parser.currentToken().isValue()) {
|
||||
list.add(parseFieldsValue(parser));
|
||||
} else if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
|
||||
list.add(null);
|
||||
} else {
|
||||
throw new IllegalStateException("expected value but got [" + parser.currentToken() + "]");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SqlQueryResponse that = (SqlQueryResponse) o;
|
||||
return Objects.equals(cursor, that.cursor) &&
|
||||
Objects.equals(columns, that.columns) &&
|
||||
Objects.equals(rows, that.rows);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(cursor, columns, rows);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,12 +3,9 @@
|
|||
* 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.plugin;
|
||||
package org.elasticsearch.xpack.sql.proto;
|
||||
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
|
@ -25,12 +22,12 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constru
|
|||
/**
|
||||
* Represent a strongly typed parameter value
|
||||
*/
|
||||
public class SqlTypedParamValue implements ToXContentObject, Writeable {
|
||||
public class SqlTypedParamValue implements ToXContentObject {
|
||||
private static final ConstructingObjectParser<SqlTypedParamValue, Void> PARSER =
|
||||
new ConstructingObjectParser<>("params", true, objects ->
|
||||
new SqlTypedParamValue(
|
||||
objects[0],
|
||||
DataType.fromEsType((String) objects[1])));
|
||||
DataType.fromEsType((String) objects[1]), objects[0]
|
||||
));
|
||||
|
||||
private static final ParseField VALUE = new ParseField("value");
|
||||
private static final ParseField TYPE = new ParseField("type");
|
||||
|
@ -43,7 +40,7 @@ public class SqlTypedParamValue implements ToXContentObject, Writeable {
|
|||
public final Object value;
|
||||
public final DataType dataType;
|
||||
|
||||
public SqlTypedParamValue(Object value, DataType dataType) {
|
||||
public SqlTypedParamValue(DataType dataType, Object value) {
|
||||
this.value = value;
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
@ -61,17 +58,6 @@ public class SqlTypedParamValue implements ToXContentObject, Writeable {
|
|||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeEnum(dataType);
|
||||
out.writeGenericValue(value);
|
||||
}
|
||||
|
||||
public SqlTypedParamValue(StreamInput in) throws IOException {
|
||||
dataType = in.readEnum(DataType.class);
|
||||
value = in.readGenericValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
|
@ -8,17 +8,18 @@ package org.elasticsearch.xpack.sql.plugin;
|
|||
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.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SqlClearCursorRequestTests extends AbstractSerializingTestCase<SqlClearCursorRequest> {
|
||||
public AbstractSqlRequest.Mode testMode;
|
||||
public Mode testMode;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
testMode = randomFrom(AbstractSqlRequest.Mode.values());
|
||||
testMode = randomFrom(Mode.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,7 +41,7 @@ public class SqlClearCursorRequestTests extends AbstractSerializingTestCase<SqlC
|
|||
protected SqlClearCursorRequest mutateInstance(SqlClearCursorRequest instance) throws IOException {
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<SqlClearCursorRequest> mutator = randomFrom(
|
||||
request -> request.mode(randomValueOtherThan(request.mode(), () -> randomFrom(AbstractSqlRequest.Mode.values()))),
|
||||
request -> request.mode(randomValueOtherThan(request.mode(), () -> randomFrom(Mode.values()))),
|
||||
request -> request.setCursor(randomValueOtherThan(request.getCursor(), SqlQueryResponseTests::randomStringCursor))
|
||||
);
|
||||
SqlClearCursorRequest newRequest = new SqlClearCursorRequest(instance.mode(), instance.getCursor());
|
||||
|
|
|
@ -27,6 +27,8 @@ public class SqlClearCursorResponseTests extends AbstractStreamableXContentTestC
|
|||
|
||||
@Override
|
||||
protected SqlClearCursorResponse doParseInstance(XContentParser parser) {
|
||||
return SqlClearCursorResponse.fromXContent(parser);
|
||||
org.elasticsearch.xpack.sql.proto.SqlClearCursorResponse response =
|
||||
org.elasticsearch.xpack.sql.proto.SqlClearCursorResponse.fromXContent(parser);
|
||||
return new SqlClearCursorResponse(response.isSucceeded());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.elasticsearch.search.SearchModule;
|
||||
import org.elasticsearch.test.AbstractSerializingTestCase;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -28,11 +30,11 @@ import static org.elasticsearch.xpack.sql.plugin.SqlTestUtils.randomFilterOrNull
|
|||
|
||||
public class SqlQueryRequestTests extends AbstractSerializingTestCase<SqlQueryRequest> {
|
||||
|
||||
public AbstractSqlRequest.Mode testMode;
|
||||
public Mode testMode;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
testMode = randomFrom(AbstractSqlRequest.Mode.values());
|
||||
testMode = randomFrom(Mode.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,11 +65,11 @@ public class SqlQueryRequestTests extends AbstractSerializingTestCase<SqlQueryRe
|
|||
List<SqlTypedParamValue> arr = new ArrayList<>(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
@SuppressWarnings("unchecked") Supplier<SqlTypedParamValue> supplier = randomFrom(
|
||||
() -> new SqlTypedParamValue(randomBoolean(), DataType.BOOLEAN),
|
||||
() -> new SqlTypedParamValue(randomLong(), DataType.LONG),
|
||||
() -> new SqlTypedParamValue(randomDouble(), DataType.DOUBLE),
|
||||
() -> new SqlTypedParamValue(null, DataType.NULL),
|
||||
() -> new SqlTypedParamValue(randomAlphaOfLength(10), DataType.KEYWORD)
|
||||
() -> new SqlTypedParamValue(DataType.BOOLEAN, randomBoolean()),
|
||||
() -> new SqlTypedParamValue(DataType.LONG, randomLong()),
|
||||
() -> new SqlTypedParamValue(DataType.DOUBLE, randomDouble()),
|
||||
() -> new SqlTypedParamValue(DataType.NULL, null),
|
||||
() -> new SqlTypedParamValue(DataType.KEYWORD, randomAlphaOfLength(10))
|
||||
);
|
||||
arr.add(supplier.get());
|
||||
}
|
||||
|
@ -93,7 +95,7 @@ public class SqlQueryRequestTests extends AbstractSerializingTestCase<SqlQueryRe
|
|||
protected SqlQueryRequest mutateInstance(SqlQueryRequest instance) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<SqlQueryRequest> mutator = randomFrom(
|
||||
request -> request.mode(randomValueOtherThan(request.mode(), () -> randomFrom(AbstractSqlRequest.Mode.values()))),
|
||||
request -> request.mode(randomValueOtherThan(request.mode(), () -> randomFrom(Mode.values()))),
|
||||
request -> request.query(randomValueOtherThan(request.query(), () -> randomAlphaOfLength(5))),
|
||||
request -> request.params(randomValueOtherThan(request.params(), this::randomParameters)),
|
||||
request -> request.timeZone(randomValueOtherThan(request.timeZone(), ESTestCase::randomTimeZone)),
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.common.xcontent.XContentHelper;
|
|||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.JDBCType;
|
||||
|
@ -114,6 +115,8 @@ public class SqlQueryResponseTests extends AbstractStreamableXContentTestCase<Sq
|
|||
|
||||
@Override
|
||||
protected SqlQueryResponse doParseInstance(XContentParser parser) {
|
||||
return SqlQueryResponse.fromXContent(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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.elasticsearch.search.SearchModule;
|
||||
import org.elasticsearch.test.AbstractSerializingTestCase;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -25,11 +26,11 @@ import static org.elasticsearch.xpack.sql.plugin.SqlTestUtils.randomFilterOrNull
|
|||
|
||||
public class SqlTranslateRequestTests extends AbstractSerializingTestCase<SqlTranslateRequest> {
|
||||
|
||||
public AbstractSqlRequest.Mode testMode;
|
||||
public Mode testMode;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
testMode = randomFrom(AbstractSqlRequest.Mode.values());
|
||||
testMode = randomFrom(Mode.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,7 +72,7 @@ public class SqlTranslateRequestTests extends AbstractSerializingTestCase<SqlTra
|
|||
request -> request.query(randomValueOtherThan(request.query(), () -> randomAlphaOfLength(5))),
|
||||
request -> request.timeZone(randomValueOtherThan(request.timeZone(), ESTestCase::randomTimeZone)),
|
||||
request -> request.fetchSize(randomValueOtherThan(request.fetchSize(), () -> between(1, Integer.MAX_VALUE))),
|
||||
request -> request.requestTimeout(randomValueOtherThan(request.requestTimeout(), () -> randomTV())),
|
||||
request -> request.requestTimeout(randomValueOtherThan(request.requestTimeout(), this::randomTV)),
|
||||
request -> request.filter(randomValueOtherThan(request.filter(),
|
||||
() -> request.filter() == null ? randomFilter(random()) : randomFilterOrNull(random())))
|
||||
);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.sql.client;
|
||||
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
|
@ -22,13 +21,14 @@ import org.elasticsearch.xpack.sql.client.shared.ClientException;
|
|||
import org.elasticsearch.xpack.sql.client.shared.ConnectionConfiguration;
|
||||
import org.elasticsearch.xpack.sql.client.shared.JreHttpUrlConnection;
|
||||
import org.elasticsearch.xpack.sql.client.shared.JreHttpUrlConnection.ResponseOrException;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlClearCursorAction;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlClearCursorRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlClearCursorResponse;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryAction;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryResponse;
|
||||
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.SqlClearCursorRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlClearCursorResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlQueryResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -50,7 +50,7 @@ public class HttpClient {
|
|||
|
||||
private final ConnectionConfiguration cfg;
|
||||
|
||||
public HttpClient(ConnectionConfiguration cfg) throws SQLException {
|
||||
public HttpClient(ConnectionConfiguration cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
|
@ -66,26 +66,25 @@ 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
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(AbstractSqlRequest.Mode.PLAIN, query, Collections.emptyList(), null,
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(Mode.PLAIN, query, Collections.emptyList(), null,
|
||||
TimeZone.getTimeZone("UTC"), fetchSize, TimeValue.timeValueMillis(cfg.queryTimeout()),
|
||||
TimeValue.timeValueMillis(cfg.pageTimeout()), ""
|
||||
);
|
||||
TimeValue.timeValueMillis(cfg.pageTimeout()));
|
||||
return query(sqlRequest);
|
||||
}
|
||||
|
||||
public SqlQueryResponse query(SqlQueryRequest sqlRequest) throws SQLException {
|
||||
return post(SqlQueryAction.REST_ENDPOINT, sqlRequest, SqlQueryResponse::fromXContent);
|
||||
return post(Protocol.SQL_QUERY_REST_ENDPOINT, sqlRequest, SqlQueryResponse::fromXContent);
|
||||
}
|
||||
|
||||
public SqlQueryResponse nextPage(String cursor) throws SQLException {
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest();
|
||||
sqlRequest.cursor(cursor);
|
||||
return post(SqlQueryAction.REST_ENDPOINT, sqlRequest, SqlQueryResponse::fromXContent);
|
||||
SqlQueryRequest sqlRequest = new SqlQueryRequest(Mode.PLAIN, cursor, TimeValue.timeValueMillis(cfg.queryTimeout()),
|
||||
TimeValue.timeValueMillis(cfg.pageTimeout()));
|
||||
return post(Protocol.SQL_QUERY_REST_ENDPOINT, sqlRequest, SqlQueryResponse::fromXContent);
|
||||
}
|
||||
|
||||
public boolean queryClose(String cursor) throws SQLException {
|
||||
SqlClearCursorResponse response = post(SqlClearCursorAction.REST_ENDPOINT,
|
||||
new SqlClearCursorRequest(AbstractSqlRequest.Mode.PLAIN, cursor),
|
||||
SqlClearCursorResponse response = post(Protocol.CLEAR_CURSOR_REST_ENDPOINT,
|
||||
new SqlClearCursorRequest(Mode.PLAIN, cursor),
|
||||
SqlClearCursorResponse::fromXContent);
|
||||
return response.isSucceeded();
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.elasticsearch.xpack.sql.optimizer.Optimizer;
|
|||
import org.elasticsearch.xpack.sql.plan.physical.EsQueryExec;
|
||||
import org.elasticsearch.xpack.sql.planner.Planner;
|
||||
import org.elasticsearch.xpack.sql.planner.PlanningException;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.session.Configuration;
|
||||
import org.elasticsearch.xpack.sql.session.Cursor;
|
||||
import org.elasticsearch.xpack.sql.session.RowSet;
|
||||
|
|
|
@ -8,7 +8,7 @@ package org.elasticsearch.xpack.sql.parser;
|
|||
import org.antlr.v4.runtime.Token;
|
||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SingleStatementContext;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysColumns;
|
|||
import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysTableTypes;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysTables;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.command.sys.SysTypes;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringContext;
|
|||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringLiteralContext;
|
||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringQueryContext;
|
||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SubqueryExpressionContext;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.elasticsearch.xpack.sql.plan.logical.Project;
|
|||
import org.elasticsearch.xpack.sql.plan.logical.SubQueryAlias;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.UnresolvedRelation;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.With;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.session.EmptyExecutable;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
|
|
|
@ -12,23 +12,25 @@ import org.elasticsearch.rest.BaseRestHandler;
|
|||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.xpack.sql.plugin.SqlClearCursorAction.REST_ENDPOINT;
|
||||
|
||||
|
||||
public class RestSqlClearCursorAction extends BaseRestHandler {
|
||||
public RestSqlClearCursorAction(Settings settings, RestController controller) {
|
||||
super(settings);
|
||||
controller.registerHandler(POST, REST_ENDPOINT, this);
|
||||
controller.registerHandler(POST, Protocol.CLEAR_CURSOR_REST_ENDPOINT, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
SqlClearCursorRequest sqlRequest;
|
||||
try (XContentParser parser = request.contentOrSourceParamParser()) {
|
||||
sqlRequest = SqlClearCursorRequest.fromXContent(parser, AbstractSqlRequest.Mode.fromString(request.param("mode")));
|
||||
sqlRequest = SqlClearCursorRequest.fromXContent(parser, Mode.fromString(request.param("mode")));
|
||||
}
|
||||
return channel -> client.executeLocally(SqlClearCursorAction.INSTANCE, sqlRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ import org.elasticsearch.rest.RestRequest;
|
|||
import org.elasticsearch.rest.RestResponse;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.rest.action.RestResponseListener;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
import org.elasticsearch.xpack.sql.session.Cursor;
|
||||
import org.elasticsearch.xpack.sql.session.Cursors;
|
||||
|
||||
|
@ -31,15 +33,15 @@ public class RestSqlQueryAction extends BaseRestHandler {
|
|||
|
||||
public RestSqlQueryAction(Settings settings, RestController controller) {
|
||||
super(settings);
|
||||
controller.registerHandler(GET, SqlQueryAction.REST_ENDPOINT, this);
|
||||
controller.registerHandler(POST, SqlQueryAction.REST_ENDPOINT, this);
|
||||
controller.registerHandler(GET, Protocol.SQL_QUERY_REST_ENDPOINT, this);
|
||||
controller.registerHandler(POST, Protocol.SQL_QUERY_REST_ENDPOINT, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
SqlQueryRequest sqlRequest;
|
||||
try (XContentParser parser = request.contentOrSourceParamParser()) {
|
||||
sqlRequest = SqlQueryRequest.fromXContent(parser, AbstractSqlRequest.Mode.fromString(request.param("mode")));
|
||||
sqlRequest = SqlQueryRequest.fromXContent(parser,Mode.fromString(request.param("mode")));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.rest.BaseRestHandler;
|
|||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -32,7 +33,7 @@ public class RestSqlTranslateAction extends BaseRestHandler {
|
|||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
SqlTranslateRequest sqlRequest;
|
||||
try (XContentParser parser = request.contentOrSourceParamParser()) {
|
||||
sqlRequest = SqlTranslateRequest.fromXContent(parser, AbstractSqlRequest.Mode.fromString(request.param("mode")));
|
||||
sqlRequest = SqlTranslateRequest.fromXContent(parser, Mode.fromString(request.param("mode")));
|
||||
}
|
||||
return channel -> client.executeLocally(SqlTranslateAction.INSTANCE, sqlRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.sql.plugin;
|
||||
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
|
@ -12,16 +14,16 @@ import java.util.function.Consumer;
|
|||
*/
|
||||
public class SqlLicenseChecker {
|
||||
|
||||
private final Consumer<AbstractSqlRequest.Mode> checkIfSqlAllowed;
|
||||
private final Consumer<Mode> checkIfSqlAllowed;
|
||||
|
||||
public SqlLicenseChecker(Consumer<AbstractSqlRequest.Mode> checkIfSqlAllowed) {
|
||||
public SqlLicenseChecker(Consumer<Mode> checkIfSqlAllowed) {
|
||||
this.checkIfSqlAllowed = checkIfSqlAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an ElasticsearchSecurityException if the specified mode is not allowed
|
||||
*/
|
||||
public void checkIfSqlAllowed(AbstractSqlRequest.Mode mode) {
|
||||
public void checkIfSqlAllowed(Mode mode) {
|
||||
checkIfSqlAllowed.accept(mode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.sql.plugin;
|
|||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.session.Cursor;
|
||||
import org.elasticsearch.xpack.sql.session.Cursors;
|
||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||
|
@ -38,17 +39,17 @@ enum TextFormat {
|
|||
final CliFormatter formatter;
|
||||
if (cursor instanceof CliFormatterCursor) {
|
||||
formatter = ((CliFormatterCursor) cursor).getCliFormatter();
|
||||
return formatter.formatWithoutHeader(response);
|
||||
return formatter.formatWithoutHeader(response.rows());
|
||||
} else {
|
||||
formatter = new CliFormatter(response);
|
||||
return formatter.formatWithHeader(response);
|
||||
formatter = new CliFormatter(response.columns(), response.rows());
|
||||
return formatter.formatWithHeader(response.columns(), response.rows());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Cursor wrapCursor(Cursor oldCursor, SqlQueryResponse response) {
|
||||
CliFormatter formatter = (oldCursor instanceof CliFormatterCursor) ?
|
||||
((CliFormatterCursor) oldCursor).getCliFormatter() : new CliFormatter(response);
|
||||
((CliFormatterCursor) oldCursor).getCliFormatter() : new CliFormatter(response.columns(), response.rows());
|
||||
return CliFormatterCursor.wrap(super.wrapCursor(oldCursor, response), formatter);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.sql.execution.PlanExecutor;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.session.Configuration;
|
||||
import org.elasticsearch.xpack.sql.session.Cursors;
|
||||
import org.elasticsearch.xpack.sql.session.RowSet;
|
||||
|
@ -26,7 +27,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static org.elasticsearch.xpack.sql.plugin.AbstractSqlRequest.Mode.JDBC;
|
||||
import static org.elasticsearch.xpack.sql.proto.Mode.JDBC;
|
||||
|
||||
public class TransportSqlQueryAction extends HandledTransportAction<SqlQueryRequest, SqlQueryResponse> {
|
||||
private final PlanExecutor planExecutor;
|
||||
|
|
|
@ -9,16 +9,14 @@ import org.elasticsearch.common.Nullable;
|
|||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlQueryRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.Protocol;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
// Typed object holding properties for a given action
|
||||
public class Configuration {
|
||||
public static final Configuration DEFAULT = new Configuration(TimeZone.getTimeZone("UTC"),
|
||||
AbstractSqlQueryRequest.DEFAULT_FETCH_SIZE,
|
||||
AbstractSqlQueryRequest.DEFAULT_REQUEST_TIMEOUT,
|
||||
AbstractSqlQueryRequest.DEFAULT_PAGE_TIMEOUT,
|
||||
null);
|
||||
Protocol.FETCH_SIZE, Protocol.REQUEST_TIMEOUT, Protocol.PAGE_TIMEOUT, null);
|
||||
|
||||
private TimeZone timeZone;
|
||||
private int pageSize;
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.elasticsearch.xpack.sql.plan.TableIdentifier;
|
|||
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
|
||||
import org.elasticsearch.xpack.sql.plan.physical.PhysicalPlan;
|
||||
import org.elasticsearch.xpack.sql.planner.Planner;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.rule.RuleExecutor;
|
||||
|
||||
import java.util.List;
|
||||
|
|
|
@ -7,10 +7,10 @@ package org.elasticsearch.xpack.sql.action;
|
|||
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.support.WriteRequest;
|
||||
import org.elasticsearch.xpack.sql.plugin.AbstractSqlRequest.Mode;
|
||||
import org.elasticsearch.xpack.sql.plugin.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryAction;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.proto.Mode;
|
||||
|
||||
import java.sql.JDBCType;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.elasticsearch.test.ESTestCase;
|
|||
import org.elasticsearch.xpack.sql.SqlException;
|
||||
import org.elasticsearch.xpack.sql.plugin.CliFormatter;
|
||||
import org.elasticsearch.xpack.sql.plugin.CliFormatterCursor;
|
||||
import org.elasticsearch.xpack.sql.plugin.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlQueryResponse;
|
||||
import org.elasticsearch.xpack.sql.session.Configuration;
|
||||
import org.elasticsearch.xpack.sql.session.Cursor;
|
||||
|
@ -80,7 +80,8 @@ public class CursorTests extends ESTestCase {
|
|||
() -> {
|
||||
SqlQueryResponse response = createRandomSqlResponse();
|
||||
if (response.columns() != null && response.rows() != null) {
|
||||
return CliFormatterCursor.wrap(ScrollCursorTests.randomScrollCursor(), new CliFormatter(response));
|
||||
return CliFormatterCursor.wrap(ScrollCursorTests.randomScrollCursor(),
|
||||
new CliFormatter(response.columns(), response.rows()));
|
||||
} else {
|
||||
return ScrollCursorTests.randomScrollCursor();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Sub;
|
|||
import org.elasticsearch.xpack.sql.expression.predicate.Equals;
|
||||
import org.elasticsearch.xpack.sql.parser.ParsingException;
|
||||
import org.elasticsearch.xpack.sql.parser.SqlParser;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -28,7 +28,7 @@ public class ParameterTests extends ESTestCase {
|
|||
public void testSingleParameter() {
|
||||
Expression expression = new SqlParser().createExpression("a = \n?",
|
||||
Collections.singletonList(
|
||||
new SqlTypedParamValue("foo", DataType.KEYWORD)
|
||||
new SqlTypedParamValue(DataType.KEYWORD, "foo")
|
||||
));
|
||||
logger.info(expression);
|
||||
assertThat(expression, instanceOf(Equals.class));
|
||||
|
@ -42,10 +42,10 @@ public class ParameterTests extends ESTestCase {
|
|||
|
||||
public void testMultipleParameters() {
|
||||
Expression expression = new SqlParser().createExpression("(? + ? * ?) - ?", Arrays.asList(
|
||||
new SqlTypedParamValue(1L, DataType.LONG),
|
||||
new SqlTypedParamValue(2L, DataType.LONG),
|
||||
new SqlTypedParamValue(3L, DataType.LONG),
|
||||
new SqlTypedParamValue(4L, DataType.LONG)
|
||||
new SqlTypedParamValue(DataType.LONG, 1L),
|
||||
new SqlTypedParamValue(DataType.LONG, 2L),
|
||||
new SqlTypedParamValue(DataType.LONG, 3L),
|
||||
new SqlTypedParamValue(DataType.LONG, 4L)
|
||||
));
|
||||
assertThat(expression, instanceOf(Sub.class));
|
||||
Sub sub = (Sub) expression;
|
||||
|
@ -62,9 +62,9 @@ public class ParameterTests extends ESTestCase {
|
|||
public void testNotEnoughParameters() {
|
||||
ParsingException ex = expectThrows(ParsingException.class,
|
||||
() -> new SqlParser().createExpression("(? + ? * ?) - ?", Arrays.asList(
|
||||
new SqlTypedParamValue(1L, DataType.LONG),
|
||||
new SqlTypedParamValue(2L, DataType.LONG),
|
||||
new SqlTypedParamValue(3L, DataType.LONG)
|
||||
new SqlTypedParamValue(DataType.LONG, 1L),
|
||||
new SqlTypedParamValue(DataType.LONG, 2L),
|
||||
new SqlTypedParamValue(DataType.LONG, 3L)
|
||||
)));
|
||||
assertThat(ex.getMessage(), containsString("Not enough actual parameters"));
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.elasticsearch.test.ESTestCase;
|
|||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.regex.Like;
|
||||
import org.elasticsearch.xpack.sql.expression.regex.LikePattern;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
@ -33,7 +33,7 @@ public class LikeEscapingParsingTests extends ESTestCase {
|
|||
Expression exp = null;
|
||||
boolean parameterized = randomBoolean();
|
||||
if (parameterized) {
|
||||
exp = parser.createExpression("exp LIKE ?", singletonList(new SqlTypedParamValue(pattern, DataType.KEYWORD)));
|
||||
exp = parser.createExpression("exp LIKE ?", singletonList(new SqlTypedParamValue(DataType.KEYWORD, pattern)));
|
||||
} else {
|
||||
exp = parser.createExpression(String.format(Locale.ROOT, "exp LIKE '%s'", pattern));
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.elasticsearch.xpack.sql.analysis.index.IndexResolver.IndexType;
|
|||
import org.elasticsearch.xpack.sql.expression.function.FunctionRegistry;
|
||||
import org.elasticsearch.xpack.sql.parser.SqlParser;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.command.Command;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||
import org.elasticsearch.xpack.sql.session.SchemaRowSet;
|
||||
import org.elasticsearch.xpack.sql.session.SqlSession;
|
||||
import org.elasticsearch.xpack.sql.type.DataTypes;
|
||||
|
@ -228,7 +228,7 @@ public class SysTablesTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private SqlTypedParamValue param(Object value) {
|
||||
return new SqlTypedParamValue(value, DataTypes.fromJava(value));
|
||||
return new SqlTypedParamValue(DataTypes.fromJava(value), value);
|
||||
}
|
||||
|
||||
private Tuple<Command, SqlSession> sql(String sql, List<SqlTypedParamValue> params) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package org.elasticsearch.xpack.sql.plugin;
|
||||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
|
||||
import java.sql.JDBCType;
|
||||
import java.util.Arrays;
|
||||
|
@ -23,17 +24,17 @@ public class CliFormatterTests extends ESTestCase {
|
|||
Arrays.asList(
|
||||
Arrays.asList("15charwidedata!", 1, 6.888, 12, "rabbit"),
|
||||
Arrays.asList("dog", 1.7976931348623157E308, 123124.888, 9912, "goat")));
|
||||
private final CliFormatter formatter = new CliFormatter(firstResponse);
|
||||
private final CliFormatter formatter = new CliFormatter(firstResponse.columns(), firstResponse.rows());
|
||||
|
||||
/**
|
||||
* Tests for {@link CliFormatter#formatWithHeader(SqlQueryResponse)}, values
|
||||
* Tests for {@link CliFormatter#formatWithHeader}, values
|
||||
* of exactly the minimum column size, column names of exactly
|
||||
* the minimum column size, column headers longer than the
|
||||
* minimum column size, and values longer than the minimum
|
||||
* column size.
|
||||
*/
|
||||
public void testFormatWithHeader() {
|
||||
String[] result = formatter.formatWithHeader(firstResponse).split("\n");
|
||||
String[] result = formatter.formatWithHeader(firstResponse.columns(), firstResponse.rows()).split("\n");
|
||||
assertThat(result, arrayWithSize(4));
|
||||
assertEquals(" foo | bar |15charwidename!|superduperwidename!!!| baz ", result[0]);
|
||||
assertEquals("---------------+----------------------+---------------+---------------------+---------------", result[1]);
|
||||
|
@ -42,14 +43,14 @@ public class CliFormatterTests extends ESTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests for {@link CliFormatter#formatWithoutHeader(SqlQueryResponse)} and
|
||||
* Tests for {@link CliFormatter#formatWithoutHeader} and
|
||||
* truncation of long columns.
|
||||
*/
|
||||
public void testFormatWithoutHeader() {
|
||||
String[] result = formatter.formatWithoutHeader(new SqlQueryResponse("", null,
|
||||
String[] result = formatter.formatWithoutHeader(
|
||||
Arrays.asList(
|
||||
Arrays.asList("ohnotruncateddata", 4, 1, 77, "wombat"),
|
||||
Arrays.asList("dog", 2, 123124.888, 9912, "goat")))).split("\n");
|
||||
Arrays.asList("dog", 2, 123124.888, 9912, "goat"))).split("\n");
|
||||
assertThat(result, arrayWithSize(2));
|
||||
assertEquals("ohnotruncatedd~|4 |1 |77 |wombat ", result[0]);
|
||||
assertEquals("dog |2 |123124.888 |9912 |goat ", result[1]);
|
||||
|
@ -59,9 +60,9 @@ public class CliFormatterTests extends ESTestCase {
|
|||
* Ensure that our estimates are perfect in at least some cases.
|
||||
*/
|
||||
public void testEstimateSize() {
|
||||
assertEquals(formatter.formatWithHeader(firstResponse).length(),
|
||||
assertEquals(formatter.formatWithHeader(firstResponse.columns(), firstResponse.rows()).length(),
|
||||
formatter.estimateSize(firstResponse.rows().size() + 2));
|
||||
assertEquals(formatter.formatWithoutHeader(firstResponse).length(),
|
||||
assertEquals(formatter.formatWithoutHeader(firstResponse.rows()).length(),
|
||||
formatter.estimateSize(firstResponse.rows().size()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
|||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||
import org.elasticsearch.xpack.sql.proto.ColumnInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
Loading…
Reference in New Issue