parent
8daa854f90
commit
971299baf4
|
@ -62,7 +62,7 @@ statement
|
||||||
| SYS COLUMNS (CATALOG cluster=string)?
|
| SYS COLUMNS (CATALOG cluster=string)?
|
||||||
(TABLE tableLike=likePattern | tableIdent=tableIdentifier)?
|
(TABLE tableLike=likePattern | tableIdent=tableIdentifier)?
|
||||||
(columnPattern=likePattern)? #sysColumns
|
(columnPattern=likePattern)? #sysColumns
|
||||||
| SYS TYPES #sysTypes
|
| SYS TYPES ((PLUS | MINUS)? type=number)? #sysTypes
|
||||||
| SYS TABLE TYPES #sysTableTypes
|
| SYS TABLE TYPES #sysTableTypes
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.sql.parser;
|
||||||
import org.antlr.v4.runtime.Token;
|
import org.antlr.v4.runtime.Token;
|
||||||
import org.elasticsearch.common.Booleans;
|
import org.elasticsearch.common.Booleans;
|
||||||
import org.elasticsearch.xpack.sql.analysis.index.IndexResolver.IndexType;
|
import org.elasticsearch.xpack.sql.analysis.index.IndexResolver.IndexType;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Literal;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.DebugContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.DebugContext;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.ExplainContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.ExplainContext;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.ShowColumnsContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.ShowColumnsContext;
|
||||||
|
@ -190,7 +191,13 @@ abstract class CommandBuilder extends LogicalPlanBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SysTypes visitSysTypes(SysTypesContext ctx) {
|
public SysTypes visitSysTypes(SysTypesContext ctx) {
|
||||||
return new SysTypes(source(ctx));
|
int type = 0;
|
||||||
|
if (ctx.type != null) {
|
||||||
|
Literal value = (Literal) visit(ctx.type);
|
||||||
|
type = ((Number) value.fold()).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SysTypes(source(ctx), Integer.valueOf(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,9 +26,9 @@ import org.elasticsearch.xpack.sql.expression.function.UnresolvedFunction;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
||||||
import org.elasticsearch.xpack.sql.expression.literal.Interval;
|
import org.elasticsearch.xpack.sql.expression.literal.Interval;
|
||||||
import org.elasticsearch.xpack.sql.expression.literal.IntervalDayTime;
|
import org.elasticsearch.xpack.sql.expression.literal.IntervalDayTime;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.literal.IntervalYearMonth;
|
||||||
import org.elasticsearch.xpack.sql.expression.literal.Intervals;
|
import org.elasticsearch.xpack.sql.expression.literal.Intervals;
|
||||||
import org.elasticsearch.xpack.sql.expression.literal.Intervals.TimeUnit;
|
import org.elasticsearch.xpack.sql.expression.literal.Intervals.TimeUnit;
|
||||||
import org.elasticsearch.xpack.sql.expression.literal.IntervalYearMonth;
|
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.Range;
|
import org.elasticsearch.xpack.sql.expression.predicate.Range;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MatchQueryPredicate;
|
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MatchQueryPredicate;
|
||||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MultiMatchQueryPredicate;
|
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MultiMatchQueryPredicate;
|
||||||
|
@ -97,6 +97,7 @@ import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringContext;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringLiteralContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringLiteralContext;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringQueryContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.StringQueryContext;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SubqueryExpressionContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SubqueryExpressionContext;
|
||||||
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.SysTypesContext;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.TimeEscapedLiteralContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.TimeEscapedLiteralContext;
|
||||||
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.TimestampEscapedLiteralContext;
|
import org.elasticsearch.xpack.sql.parser.SqlBaseParser.TimestampEscapedLiteralContext;
|
||||||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue;
|
||||||
|
@ -653,12 +654,14 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
||||||
throw new ParsingException(source(ctx), siae.getMessage());
|
throw new ParsingException(source(ctx), siae.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object val = Long.valueOf(value);
|
||||||
DataType type = DataType.LONG;
|
DataType type = DataType.LONG;
|
||||||
// try to downsize to int if possible (since that's the most common type)
|
// try to downsize to int if possible (since that's the most common type)
|
||||||
if ((int) value == value) {
|
if ((int) value == value) {
|
||||||
type = DataType.INTEGER;
|
type = DataType.INTEGER;
|
||||||
|
val = Integer.valueOf((int) value);
|
||||||
}
|
}
|
||||||
return new Literal(source(ctx), value, type);
|
return new Literal(source(ctx), val, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -836,6 +839,8 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
||||||
} else if (parentCtx instanceof SqlBaseParser.IntervalContext) {
|
} else if (parentCtx instanceof SqlBaseParser.IntervalContext) {
|
||||||
IntervalContext ic = (IntervalContext) parentCtx;
|
IntervalContext ic = (IntervalContext) parentCtx;
|
||||||
return ic.sign != null && ic.sign.getType() == SqlBaseParser.MINUS;
|
return ic.sign != null && ic.sign.getType() == SqlBaseParser.MINUS;
|
||||||
|
} else if (parentCtx instanceof SqlBaseParser.SysTypesContext) {
|
||||||
|
return ((SysTypesContext) parentCtx).MINUS() != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,15 +28,23 @@ import static org.elasticsearch.xpack.sql.type.DataType.BOOLEAN;
|
||||||
import static org.elasticsearch.xpack.sql.type.DataType.INTEGER;
|
import static org.elasticsearch.xpack.sql.type.DataType.INTEGER;
|
||||||
import static org.elasticsearch.xpack.sql.type.DataType.SHORT;
|
import static org.elasticsearch.xpack.sql.type.DataType.SHORT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System command designed to be used by JDBC / ODBC for column metadata.
|
||||||
|
* In JDBC it used for {@link DatabaseMetaData#getTypeInfo()},
|
||||||
|
* in ODBC for <a href="https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgettypeinfo-function">SQLGetTypeInfo</a>
|
||||||
|
*/
|
||||||
public class SysTypes extends Command {
|
public class SysTypes extends Command {
|
||||||
|
|
||||||
public SysTypes(Location location) {
|
private final Integer type;
|
||||||
|
|
||||||
|
public SysTypes(Location location, int type) {
|
||||||
super(location);
|
super(location);
|
||||||
|
this.type = Integer.valueOf(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected NodeInfo<SysTypes> info() {
|
protected NodeInfo<SysTypes> info() {
|
||||||
return NodeInfo.create(this);
|
return NodeInfo.create(this, SysTypes::new, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,7 +74,11 @@ public class SysTypes extends Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void execute(SqlSession session, ActionListener<SchemaRowSet> listener) {
|
public final void execute(SqlSession session, ActionListener<SchemaRowSet> listener) {
|
||||||
List<List<?>> rows = Stream.of(DataType.values())
|
Stream<DataType> values = Stream.of(DataType.values());
|
||||||
|
if (type.intValue() != 0) {
|
||||||
|
values = values.filter(t -> type.equals(t.sqlType.getVendorTypeNumber()));
|
||||||
|
}
|
||||||
|
List<List<?>> rows = values
|
||||||
// sort by SQL int type (that's what the JDBC/ODBC specs want) followed by name
|
// sort by SQL int type (that's what the JDBC/ODBC specs want) followed by name
|
||||||
.sorted(Comparator.comparing((DataType t) -> t.sqlType.getVendorTypeNumber()).thenComparing(DataType::sqlName))
|
.sorted(Comparator.comparing((DataType t) -> t.sqlType.getVendorTypeNumber()).thenComparing(DataType::sqlName))
|
||||||
.map(t -> asList(t.esType.toUpperCase(Locale.ROOT),
|
.map(t -> asList(t.esType.toUpperCase(Locale.ROOT),
|
||||||
|
@ -105,7 +117,7 @@ public class SysTypes extends Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return getClass().hashCode();
|
return type.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -118,6 +130,6 @@ public class SysTypes extends Command {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return type.equals(((SysTypes) obj).type);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,14 +39,15 @@ public class SysTableTypesTests extends ESTestCase {
|
||||||
return new Tuple<>(cmd, session);
|
return new Tuple<>(cmd, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSysCatalogs() throws Exception {
|
public void testSysTableTypes() throws Exception {
|
||||||
Tuple<Command, SqlSession> sql = sql("SYS TABLE TYPES");
|
Tuple<Command, SqlSession> sql = sql("SYS TABLE TYPES");
|
||||||
|
|
||||||
sql.v1().execute(sql.v2(), ActionListener.wrap(r -> {
|
sql.v1().execute(sql.v2(), ActionListener.wrap(r -> {
|
||||||
assertEquals(2, r.size());
|
assertEquals(2, r.size());
|
||||||
assertEquals("ALIAS", r.column(0));
|
assertEquals("ALIAS", r.column(0));
|
||||||
r.advanceRow();
|
assertTrue(r.advanceRow());
|
||||||
assertEquals("BASE TABLE", r.column(0));
|
assertEquals("BASE TABLE", r.column(0));
|
||||||
}, ex -> fail(ex.getMessage())));
|
}, ex -> fail(ex.getMessage())));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* 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.plan.logical.command.sys;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.xpack.sql.analysis.analyzer.Analyzer;
|
||||||
|
import org.elasticsearch.xpack.sql.analysis.index.EsIndex;
|
||||||
|
import org.elasticsearch.xpack.sql.analysis.index.IndexResolution;
|
||||||
|
import org.elasticsearch.xpack.sql.analysis.index.IndexResolver;
|
||||||
|
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.session.SqlSession;
|
||||||
|
import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
|
import org.elasticsearch.xpack.sql.type.TypesTests;
|
||||||
|
|
||||||
|
import java.sql.JDBCType;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static org.elasticsearch.action.ActionListener.wrap;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class SysTypesTests extends ESTestCase {
|
||||||
|
|
||||||
|
private final SqlParser parser = new SqlParser();
|
||||||
|
|
||||||
|
private Tuple<Command, SqlSession> sql(String sql) {
|
||||||
|
EsIndex test = new EsIndex("test", TypesTests.loadMapping("mapping-multi-field-with-nested.json", true));
|
||||||
|
Analyzer analyzer = new Analyzer(new FunctionRegistry(), IndexResolution.valid(test), TimeZone.getTimeZone("UTC"));
|
||||||
|
Command cmd = (Command) analyzer.analyze(parser.createStatement(sql), true);
|
||||||
|
|
||||||
|
IndexResolver resolver = mock(IndexResolver.class);
|
||||||
|
SqlSession session = new SqlSession(null, null, null, resolver, null, null, null);
|
||||||
|
return new Tuple<>(cmd, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSysTypes() throws Exception {
|
||||||
|
Command cmd = sql("SYS TYPES").v1();
|
||||||
|
|
||||||
|
List<String> names = asList("BYTE", "LONG", "BINARY", "NULL", "INTEGER", "SHORT", "HALF_FLOAT", "SCALED_FLOAT", "FLOAT", "DOUBLE",
|
||||||
|
"KEYWORD", "TEXT", "IP", "BOOLEAN", "DATE",
|
||||||
|
"INTERVAL_YEAR", "INTERVAL_MONTH", "INTERVAL_DAY", "INTERVAL_HOUR", "INTERVAL_MINUTE", "INTERVAL_SECOND",
|
||||||
|
"INTERVAL_YEAR_TO_MONTH", "INTERVAL_DAY_TO_HOUR", "INTERVAL_DAY_TO_MINUTE", "INTERVAL_DAY_TO_SECOND",
|
||||||
|
"INTERVAL_HOUR_TO_MINUTE", "INTERVAL_HOUR_TO_SECOND", "INTERVAL_MINUTE_TO_SECOND",
|
||||||
|
"UNSUPPORTED", "OBJECT", "NESTED");
|
||||||
|
|
||||||
|
cmd.execute(null, wrap(r -> {
|
||||||
|
assertEquals(19, r.columnCount());
|
||||||
|
assertEquals(DataType.values().length, r.size());
|
||||||
|
assertFalse(r.schema().types().contains(DataType.NULL));
|
||||||
|
// test numeric as signed
|
||||||
|
assertFalse(r.column(9, Boolean.class));
|
||||||
|
// make sure precision is returned as boolean (not int)
|
||||||
|
assertFalse(r.column(10, Boolean.class));
|
||||||
|
// no auto-increment
|
||||||
|
assertFalse(r.column(11, Boolean.class));
|
||||||
|
|
||||||
|
for (int i = 0; i < r.size(); i++) {
|
||||||
|
assertEquals(names.get(i), r.column(0));
|
||||||
|
r.advanceRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
}, ex -> fail(ex.getMessage())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSysTypesDefaultFiltering() throws Exception {
|
||||||
|
Command cmd = sql("SYS TYPES 0").v1();
|
||||||
|
|
||||||
|
cmd.execute(null, wrap(r -> {
|
||||||
|
assertEquals(DataType.values().length, r.size());
|
||||||
|
}, ex -> fail(ex.getMessage())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSysTypesPositiveFiltering() throws Exception {
|
||||||
|
// boolean = 16
|
||||||
|
Command cmd = sql("SYS TYPES " + JDBCType.BOOLEAN.getVendorTypeNumber()).v1();
|
||||||
|
|
||||||
|
cmd.execute(null, wrap(r -> {
|
||||||
|
assertEquals(1, r.size());
|
||||||
|
assertEquals("BOOLEAN", r.column(0));
|
||||||
|
}, ex -> fail(ex.getMessage())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSysTypesNegativeFiltering() throws Exception {
|
||||||
|
Command cmd = sql("SYS TYPES " + JDBCType.TINYINT.getVendorTypeNumber()).v1();
|
||||||
|
|
||||||
|
cmd.execute(null, wrap(r -> {
|
||||||
|
assertEquals(1, r.size());
|
||||||
|
assertEquals("BYTE", r.column(0));
|
||||||
|
}, ex -> fail(ex.getMessage())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSysTypesMultipleMatches() throws Exception {
|
||||||
|
Command cmd = sql("SYS TYPES " + JDBCType.VARCHAR.getVendorTypeNumber()).v1();
|
||||||
|
|
||||||
|
cmd.execute(null, wrap(r -> {
|
||||||
|
assertEquals(3, r.size());
|
||||||
|
assertEquals("KEYWORD", r.column(0));
|
||||||
|
assertTrue(r.advanceRow());
|
||||||
|
assertEquals("TEXT", r.column(0));
|
||||||
|
assertTrue(r.advanceRow());
|
||||||
|
assertEquals("IP", r.column(0));
|
||||||
|
}, ex -> fail(ex.getMessage())));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue