mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 10:25:15 +00:00
SQL: Introduce support for NULL values (#34573)
Make SQL aware of missing and/or unmapped fields treating them as NULL Make _all_ functions and operators null-safe aware, including when used in filtering or sorting contexts Add missing and null-safe doc value extractor Modify dataset to have null fields spread around (in groups of 10) Enforce missing last and unmapped_type inside sorting Consolidate Predicate templating and declaration Add support for Like/RLike in scripting Generalize NULLS LAST/FIRST Introduce early schema declaration for CSV spec tests: to keep the doc snippets in place (introduce schema:: prefix for declaration) upfront. Fix #32079
This commit is contained in:
parent
4236358f5d
commit
52104aac27
@ -43,7 +43,9 @@ Which returns:
|
||||
"sort" : [
|
||||
{
|
||||
"page_count" : {
|
||||
"order" : "desc"
|
||||
"order" : "desc",
|
||||
"missing" : "_first",
|
||||
"unmapped_type" : "short"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -88,7 +88,7 @@ queryTerm
|
||||
;
|
||||
|
||||
orderBy
|
||||
: expression ordering=(ASC | DESC)?
|
||||
: expression ordering=(ASC | DESC)? (NULLS nullOrdering=(FIRST | LAST))?
|
||||
;
|
||||
|
||||
querySpecification
|
||||
@ -357,6 +357,7 @@ EXISTS: 'EXISTS';
|
||||
EXPLAIN: 'EXPLAIN';
|
||||
EXTRACT: 'EXTRACT';
|
||||
FALSE: 'FALSE';
|
||||
FIRST: 'FIRST';
|
||||
FORMAT: 'FORMAT';
|
||||
FROM: 'FROM';
|
||||
FULL: 'FULL';
|
||||
@ -368,6 +369,7 @@ IN: 'IN';
|
||||
INNER: 'INNER';
|
||||
IS: 'IS';
|
||||
JOIN: 'JOIN';
|
||||
LAST: 'LAST';
|
||||
LEFT: 'LEFT';
|
||||
LIKE: 'LIKE';
|
||||
LIMIT: 'LIMIT';
|
||||
@ -376,6 +378,7 @@ MATCH: 'MATCH';
|
||||
NATURAL: 'NATURAL';
|
||||
NOT: 'NOT';
|
||||
NULL: 'NULL';
|
||||
NULLS: 'NULLS';
|
||||
ON: 'ON';
|
||||
OPTIMIZED: 'OPTIMIZED';
|
||||
OR: 'OR';
|
||||
|
@ -25,85 +25,88 @@ EXISTS=24
|
||||
EXPLAIN=25
|
||||
EXTRACT=26
|
||||
FALSE=27
|
||||
FORMAT=28
|
||||
FROM=29
|
||||
FULL=30
|
||||
FUNCTIONS=31
|
||||
GRAPHVIZ=32
|
||||
GROUP=33
|
||||
HAVING=34
|
||||
IN=35
|
||||
INNER=36
|
||||
IS=37
|
||||
JOIN=38
|
||||
LEFT=39
|
||||
LIKE=40
|
||||
LIMIT=41
|
||||
MAPPED=42
|
||||
MATCH=43
|
||||
NATURAL=44
|
||||
NOT=45
|
||||
NULL=46
|
||||
ON=47
|
||||
OPTIMIZED=48
|
||||
OR=49
|
||||
ORDER=50
|
||||
OUTER=51
|
||||
PARSED=52
|
||||
PHYSICAL=53
|
||||
PLAN=54
|
||||
RIGHT=55
|
||||
RLIKE=56
|
||||
QUERY=57
|
||||
SCHEMAS=58
|
||||
SELECT=59
|
||||
SHOW=60
|
||||
SYS=61
|
||||
TABLE=62
|
||||
TABLES=63
|
||||
TEXT=64
|
||||
TRUE=65
|
||||
TYPE=66
|
||||
TYPES=67
|
||||
USING=68
|
||||
VERIFY=69
|
||||
WHERE=70
|
||||
WITH=71
|
||||
ESCAPE_ESC=72
|
||||
FUNCTION_ESC=73
|
||||
LIMIT_ESC=74
|
||||
DATE_ESC=75
|
||||
TIME_ESC=76
|
||||
TIMESTAMP_ESC=77
|
||||
GUID_ESC=78
|
||||
ESC_END=79
|
||||
EQ=80
|
||||
NEQ=81
|
||||
LT=82
|
||||
LTE=83
|
||||
GT=84
|
||||
GTE=85
|
||||
PLUS=86
|
||||
MINUS=87
|
||||
ASTERISK=88
|
||||
SLASH=89
|
||||
PERCENT=90
|
||||
CONCAT=91
|
||||
DOT=92
|
||||
PARAM=93
|
||||
STRING=94
|
||||
INTEGER_VALUE=95
|
||||
DECIMAL_VALUE=96
|
||||
IDENTIFIER=97
|
||||
DIGIT_IDENTIFIER=98
|
||||
TABLE_IDENTIFIER=99
|
||||
QUOTED_IDENTIFIER=100
|
||||
BACKQUOTED_IDENTIFIER=101
|
||||
SIMPLE_COMMENT=102
|
||||
BRACKETED_COMMENT=103
|
||||
WS=104
|
||||
UNRECOGNIZED=105
|
||||
DELIMITER=106
|
||||
FIRST=28
|
||||
FORMAT=29
|
||||
FROM=30
|
||||
FULL=31
|
||||
FUNCTIONS=32
|
||||
GRAPHVIZ=33
|
||||
GROUP=34
|
||||
HAVING=35
|
||||
IN=36
|
||||
INNER=37
|
||||
IS=38
|
||||
JOIN=39
|
||||
LAST=40
|
||||
LEFT=41
|
||||
LIKE=42
|
||||
LIMIT=43
|
||||
MAPPED=44
|
||||
MATCH=45
|
||||
NATURAL=46
|
||||
NOT=47
|
||||
NULL=48
|
||||
NULLS=49
|
||||
ON=50
|
||||
OPTIMIZED=51
|
||||
OR=52
|
||||
ORDER=53
|
||||
OUTER=54
|
||||
PARSED=55
|
||||
PHYSICAL=56
|
||||
PLAN=57
|
||||
RIGHT=58
|
||||
RLIKE=59
|
||||
QUERY=60
|
||||
SCHEMAS=61
|
||||
SELECT=62
|
||||
SHOW=63
|
||||
SYS=64
|
||||
TABLE=65
|
||||
TABLES=66
|
||||
TEXT=67
|
||||
TRUE=68
|
||||
TYPE=69
|
||||
TYPES=70
|
||||
USING=71
|
||||
VERIFY=72
|
||||
WHERE=73
|
||||
WITH=74
|
||||
ESCAPE_ESC=75
|
||||
FUNCTION_ESC=76
|
||||
LIMIT_ESC=77
|
||||
DATE_ESC=78
|
||||
TIME_ESC=79
|
||||
TIMESTAMP_ESC=80
|
||||
GUID_ESC=81
|
||||
ESC_END=82
|
||||
EQ=83
|
||||
NEQ=84
|
||||
LT=85
|
||||
LTE=86
|
||||
GT=87
|
||||
GTE=88
|
||||
PLUS=89
|
||||
MINUS=90
|
||||
ASTERISK=91
|
||||
SLASH=92
|
||||
PERCENT=93
|
||||
CONCAT=94
|
||||
DOT=95
|
||||
PARAM=96
|
||||
STRING=97
|
||||
INTEGER_VALUE=98
|
||||
DECIMAL_VALUE=99
|
||||
IDENTIFIER=100
|
||||
DIGIT_IDENTIFIER=101
|
||||
TABLE_IDENTIFIER=102
|
||||
QUOTED_IDENTIFIER=103
|
||||
BACKQUOTED_IDENTIFIER=104
|
||||
SIMPLE_COMMENT=105
|
||||
BRACKETED_COMMENT=106
|
||||
WS=107
|
||||
UNRECOGNIZED=108
|
||||
DELIMITER=109
|
||||
'('=1
|
||||
')'=2
|
||||
','=3
|
||||
@ -131,68 +134,71 @@ DELIMITER=106
|
||||
'EXPLAIN'=25
|
||||
'EXTRACT'=26
|
||||
'FALSE'=27
|
||||
'FORMAT'=28
|
||||
'FROM'=29
|
||||
'FULL'=30
|
||||
'FUNCTIONS'=31
|
||||
'GRAPHVIZ'=32
|
||||
'GROUP'=33
|
||||
'HAVING'=34
|
||||
'IN'=35
|
||||
'INNER'=36
|
||||
'IS'=37
|
||||
'JOIN'=38
|
||||
'LEFT'=39
|
||||
'LIKE'=40
|
||||
'LIMIT'=41
|
||||
'MAPPED'=42
|
||||
'MATCH'=43
|
||||
'NATURAL'=44
|
||||
'NOT'=45
|
||||
'NULL'=46
|
||||
'ON'=47
|
||||
'OPTIMIZED'=48
|
||||
'OR'=49
|
||||
'ORDER'=50
|
||||
'OUTER'=51
|
||||
'PARSED'=52
|
||||
'PHYSICAL'=53
|
||||
'PLAN'=54
|
||||
'RIGHT'=55
|
||||
'RLIKE'=56
|
||||
'QUERY'=57
|
||||
'SCHEMAS'=58
|
||||
'SELECT'=59
|
||||
'SHOW'=60
|
||||
'SYS'=61
|
||||
'TABLE'=62
|
||||
'TABLES'=63
|
||||
'TEXT'=64
|
||||
'TRUE'=65
|
||||
'TYPE'=66
|
||||
'TYPES'=67
|
||||
'USING'=68
|
||||
'VERIFY'=69
|
||||
'WHERE'=70
|
||||
'WITH'=71
|
||||
'{ESCAPE'=72
|
||||
'{FN'=73
|
||||
'{LIMIT'=74
|
||||
'{D'=75
|
||||
'{T'=76
|
||||
'{TS'=77
|
||||
'{GUID'=78
|
||||
'}'=79
|
||||
'='=80
|
||||
'<'=82
|
||||
'<='=83
|
||||
'>'=84
|
||||
'>='=85
|
||||
'+'=86
|
||||
'-'=87
|
||||
'*'=88
|
||||
'/'=89
|
||||
'%'=90
|
||||
'||'=91
|
||||
'.'=92
|
||||
'?'=93
|
||||
'FIRST'=28
|
||||
'FORMAT'=29
|
||||
'FROM'=30
|
||||
'FULL'=31
|
||||
'FUNCTIONS'=32
|
||||
'GRAPHVIZ'=33
|
||||
'GROUP'=34
|
||||
'HAVING'=35
|
||||
'IN'=36
|
||||
'INNER'=37
|
||||
'IS'=38
|
||||
'JOIN'=39
|
||||
'LAST'=40
|
||||
'LEFT'=41
|
||||
'LIKE'=42
|
||||
'LIMIT'=43
|
||||
'MAPPED'=44
|
||||
'MATCH'=45
|
||||
'NATURAL'=46
|
||||
'NOT'=47
|
||||
'NULL'=48
|
||||
'NULLS'=49
|
||||
'ON'=50
|
||||
'OPTIMIZED'=51
|
||||
'OR'=52
|
||||
'ORDER'=53
|
||||
'OUTER'=54
|
||||
'PARSED'=55
|
||||
'PHYSICAL'=56
|
||||
'PLAN'=57
|
||||
'RIGHT'=58
|
||||
'RLIKE'=59
|
||||
'QUERY'=60
|
||||
'SCHEMAS'=61
|
||||
'SELECT'=62
|
||||
'SHOW'=63
|
||||
'SYS'=64
|
||||
'TABLE'=65
|
||||
'TABLES'=66
|
||||
'TEXT'=67
|
||||
'TRUE'=68
|
||||
'TYPE'=69
|
||||
'TYPES'=70
|
||||
'USING'=71
|
||||
'VERIFY'=72
|
||||
'WHERE'=73
|
||||
'WITH'=74
|
||||
'{ESCAPE'=75
|
||||
'{FN'=76
|
||||
'{LIMIT'=77
|
||||
'{D'=78
|
||||
'{T'=79
|
||||
'{TS'=80
|
||||
'{GUID'=81
|
||||
'}'=82
|
||||
'='=83
|
||||
'<'=85
|
||||
'<='=86
|
||||
'>'=87
|
||||
'>='=88
|
||||
'+'=89
|
||||
'-'=90
|
||||
'*'=91
|
||||
'/'=92
|
||||
'%'=93
|
||||
'||'=94
|
||||
'.'=95
|
||||
'?'=96
|
||||
|
@ -25,84 +25,87 @@ EXISTS=24
|
||||
EXPLAIN=25
|
||||
EXTRACT=26
|
||||
FALSE=27
|
||||
FORMAT=28
|
||||
FROM=29
|
||||
FULL=30
|
||||
FUNCTIONS=31
|
||||
GRAPHVIZ=32
|
||||
GROUP=33
|
||||
HAVING=34
|
||||
IN=35
|
||||
INNER=36
|
||||
IS=37
|
||||
JOIN=38
|
||||
LEFT=39
|
||||
LIKE=40
|
||||
LIMIT=41
|
||||
MAPPED=42
|
||||
MATCH=43
|
||||
NATURAL=44
|
||||
NOT=45
|
||||
NULL=46
|
||||
ON=47
|
||||
OPTIMIZED=48
|
||||
OR=49
|
||||
ORDER=50
|
||||
OUTER=51
|
||||
PARSED=52
|
||||
PHYSICAL=53
|
||||
PLAN=54
|
||||
RIGHT=55
|
||||
RLIKE=56
|
||||
QUERY=57
|
||||
SCHEMAS=58
|
||||
SELECT=59
|
||||
SHOW=60
|
||||
SYS=61
|
||||
TABLE=62
|
||||
TABLES=63
|
||||
TEXT=64
|
||||
TRUE=65
|
||||
TYPE=66
|
||||
TYPES=67
|
||||
USING=68
|
||||
VERIFY=69
|
||||
WHERE=70
|
||||
WITH=71
|
||||
ESCAPE_ESC=72
|
||||
FUNCTION_ESC=73
|
||||
LIMIT_ESC=74
|
||||
DATE_ESC=75
|
||||
TIME_ESC=76
|
||||
TIMESTAMP_ESC=77
|
||||
GUID_ESC=78
|
||||
ESC_END=79
|
||||
EQ=80
|
||||
NEQ=81
|
||||
LT=82
|
||||
LTE=83
|
||||
GT=84
|
||||
GTE=85
|
||||
PLUS=86
|
||||
MINUS=87
|
||||
ASTERISK=88
|
||||
SLASH=89
|
||||
PERCENT=90
|
||||
CONCAT=91
|
||||
DOT=92
|
||||
PARAM=93
|
||||
STRING=94
|
||||
INTEGER_VALUE=95
|
||||
DECIMAL_VALUE=96
|
||||
IDENTIFIER=97
|
||||
DIGIT_IDENTIFIER=98
|
||||
TABLE_IDENTIFIER=99
|
||||
QUOTED_IDENTIFIER=100
|
||||
BACKQUOTED_IDENTIFIER=101
|
||||
SIMPLE_COMMENT=102
|
||||
BRACKETED_COMMENT=103
|
||||
WS=104
|
||||
UNRECOGNIZED=105
|
||||
FIRST=28
|
||||
FORMAT=29
|
||||
FROM=30
|
||||
FULL=31
|
||||
FUNCTIONS=32
|
||||
GRAPHVIZ=33
|
||||
GROUP=34
|
||||
HAVING=35
|
||||
IN=36
|
||||
INNER=37
|
||||
IS=38
|
||||
JOIN=39
|
||||
LAST=40
|
||||
LEFT=41
|
||||
LIKE=42
|
||||
LIMIT=43
|
||||
MAPPED=44
|
||||
MATCH=45
|
||||
NATURAL=46
|
||||
NOT=47
|
||||
NULL=48
|
||||
NULLS=49
|
||||
ON=50
|
||||
OPTIMIZED=51
|
||||
OR=52
|
||||
ORDER=53
|
||||
OUTER=54
|
||||
PARSED=55
|
||||
PHYSICAL=56
|
||||
PLAN=57
|
||||
RIGHT=58
|
||||
RLIKE=59
|
||||
QUERY=60
|
||||
SCHEMAS=61
|
||||
SELECT=62
|
||||
SHOW=63
|
||||
SYS=64
|
||||
TABLE=65
|
||||
TABLES=66
|
||||
TEXT=67
|
||||
TRUE=68
|
||||
TYPE=69
|
||||
TYPES=70
|
||||
USING=71
|
||||
VERIFY=72
|
||||
WHERE=73
|
||||
WITH=74
|
||||
ESCAPE_ESC=75
|
||||
FUNCTION_ESC=76
|
||||
LIMIT_ESC=77
|
||||
DATE_ESC=78
|
||||
TIME_ESC=79
|
||||
TIMESTAMP_ESC=80
|
||||
GUID_ESC=81
|
||||
ESC_END=82
|
||||
EQ=83
|
||||
NEQ=84
|
||||
LT=85
|
||||
LTE=86
|
||||
GT=87
|
||||
GTE=88
|
||||
PLUS=89
|
||||
MINUS=90
|
||||
ASTERISK=91
|
||||
SLASH=92
|
||||
PERCENT=93
|
||||
CONCAT=94
|
||||
DOT=95
|
||||
PARAM=96
|
||||
STRING=97
|
||||
INTEGER_VALUE=98
|
||||
DECIMAL_VALUE=99
|
||||
IDENTIFIER=100
|
||||
DIGIT_IDENTIFIER=101
|
||||
TABLE_IDENTIFIER=102
|
||||
QUOTED_IDENTIFIER=103
|
||||
BACKQUOTED_IDENTIFIER=104
|
||||
SIMPLE_COMMENT=105
|
||||
BRACKETED_COMMENT=106
|
||||
WS=107
|
||||
UNRECOGNIZED=108
|
||||
'('=1
|
||||
')'=2
|
||||
','=3
|
||||
@ -130,68 +133,71 @@ UNRECOGNIZED=105
|
||||
'EXPLAIN'=25
|
||||
'EXTRACT'=26
|
||||
'FALSE'=27
|
||||
'FORMAT'=28
|
||||
'FROM'=29
|
||||
'FULL'=30
|
||||
'FUNCTIONS'=31
|
||||
'GRAPHVIZ'=32
|
||||
'GROUP'=33
|
||||
'HAVING'=34
|
||||
'IN'=35
|
||||
'INNER'=36
|
||||
'IS'=37
|
||||
'JOIN'=38
|
||||
'LEFT'=39
|
||||
'LIKE'=40
|
||||
'LIMIT'=41
|
||||
'MAPPED'=42
|
||||
'MATCH'=43
|
||||
'NATURAL'=44
|
||||
'NOT'=45
|
||||
'NULL'=46
|
||||
'ON'=47
|
||||
'OPTIMIZED'=48
|
||||
'OR'=49
|
||||
'ORDER'=50
|
||||
'OUTER'=51
|
||||
'PARSED'=52
|
||||
'PHYSICAL'=53
|
||||
'PLAN'=54
|
||||
'RIGHT'=55
|
||||
'RLIKE'=56
|
||||
'QUERY'=57
|
||||
'SCHEMAS'=58
|
||||
'SELECT'=59
|
||||
'SHOW'=60
|
||||
'SYS'=61
|
||||
'TABLE'=62
|
||||
'TABLES'=63
|
||||
'TEXT'=64
|
||||
'TRUE'=65
|
||||
'TYPE'=66
|
||||
'TYPES'=67
|
||||
'USING'=68
|
||||
'VERIFY'=69
|
||||
'WHERE'=70
|
||||
'WITH'=71
|
||||
'{ESCAPE'=72
|
||||
'{FN'=73
|
||||
'{LIMIT'=74
|
||||
'{D'=75
|
||||
'{T'=76
|
||||
'{TS'=77
|
||||
'{GUID'=78
|
||||
'}'=79
|
||||
'='=80
|
||||
'<'=82
|
||||
'<='=83
|
||||
'>'=84
|
||||
'>='=85
|
||||
'+'=86
|
||||
'-'=87
|
||||
'*'=88
|
||||
'/'=89
|
||||
'%'=90
|
||||
'||'=91
|
||||
'.'=92
|
||||
'?'=93
|
||||
'FIRST'=28
|
||||
'FORMAT'=29
|
||||
'FROM'=30
|
||||
'FULL'=31
|
||||
'FUNCTIONS'=32
|
||||
'GRAPHVIZ'=33
|
||||
'GROUP'=34
|
||||
'HAVING'=35
|
||||
'IN'=36
|
||||
'INNER'=37
|
||||
'IS'=38
|
||||
'JOIN'=39
|
||||
'LAST'=40
|
||||
'LEFT'=41
|
||||
'LIKE'=42
|
||||
'LIMIT'=43
|
||||
'MAPPED'=44
|
||||
'MATCH'=45
|
||||
'NATURAL'=46
|
||||
'NOT'=47
|
||||
'NULL'=48
|
||||
'NULLS'=49
|
||||
'ON'=50
|
||||
'OPTIMIZED'=51
|
||||
'OR'=52
|
||||
'ORDER'=53
|
||||
'OUTER'=54
|
||||
'PARSED'=55
|
||||
'PHYSICAL'=56
|
||||
'PLAN'=57
|
||||
'RIGHT'=58
|
||||
'RLIKE'=59
|
||||
'QUERY'=60
|
||||
'SCHEMAS'=61
|
||||
'SELECT'=62
|
||||
'SHOW'=63
|
||||
'SYS'=64
|
||||
'TABLE'=65
|
||||
'TABLES'=66
|
||||
'TEXT'=67
|
||||
'TRUE'=68
|
||||
'TYPE'=69
|
||||
'TYPES'=70
|
||||
'USING'=71
|
||||
'VERIFY'=72
|
||||
'WHERE'=73
|
||||
'WITH'=74
|
||||
'{ESCAPE'=75
|
||||
'{FN'=76
|
||||
'{LIMIT'=77
|
||||
'{D'=78
|
||||
'{T'=79
|
||||
'{TS'=80
|
||||
'{GUID'=81
|
||||
'}'=82
|
||||
'='=83
|
||||
'<'=85
|
||||
'<='=86
|
||||
'>'=87
|
||||
'>='=88
|
||||
'+'=89
|
||||
'-'=90
|
||||
'*'=91
|
||||
'/'=92
|
||||
'%'=93
|
||||
'||'=94
|
||||
'.'=95
|
||||
'?'=96
|
||||
|
@ -487,7 +487,8 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
|
||||
if (ordinal != null) {
|
||||
changed = true;
|
||||
if (ordinal > 0 && ordinal <= max) {
|
||||
newOrder.add(new Order(order.location(), orderBy.child().output().get(ordinal - 1), order.direction()));
|
||||
newOrder.add(new Order(order.location(), orderBy.child().output().get(ordinal - 1), order.direction(),
|
||||
order.nullsPosition()));
|
||||
}
|
||||
else {
|
||||
throw new AnalysisException(order, "Invalid %d specified in OrderBy (valid range is [1, %d])", ordinal, max);
|
||||
|
@ -110,9 +110,15 @@ public abstract class SourceGenerator {
|
||||
FieldAttribute fa = (FieldAttribute) attr;
|
||||
fa = fa.isInexact() ? fa.exactAttribute() : fa;
|
||||
|
||||
sortBuilder = fieldSort(fa.name());
|
||||
sortBuilder = fieldSort(fa.name())
|
||||
.missing(as.missing().position())
|
||||
.unmappedType(fa.dataType().esType);
|
||||
|
||||
if (fa.isNested()) {
|
||||
FieldSortBuilder fieldSort = fieldSort(fa.name());
|
||||
FieldSortBuilder fieldSort = fieldSort(fa.name())
|
||||
.missing(as.missing().position())
|
||||
.unmappedType(fa.dataType().esType);
|
||||
|
||||
NestedSortBuilder newSort = new NestedSortBuilder(fa.nestedParent().name());
|
||||
NestedSortBuilder nestedSort = fieldSort.getNestedSort();
|
||||
|
||||
|
@ -107,7 +107,9 @@ public class CompositeKeyExtractor implements BucketExtractor {
|
||||
Object object = ((Map<?, ?>) m).get(key);
|
||||
|
||||
if (timeZone != null) {
|
||||
if (object instanceof Long) {
|
||||
if (object == null) {
|
||||
return object;
|
||||
} else if (object instanceof Long) {
|
||||
object = new DateTime(((Long) object).longValue(), DateTimeZone.forTimeZone(timeZone));
|
||||
} else {
|
||||
throw new SqlIllegalArgumentException("Invalid date key returned: {}", object);
|
||||
|
@ -20,18 +20,24 @@ public class Order extends Expression {
|
||||
ASC, DESC
|
||||
}
|
||||
|
||||
public enum NullsPosition {
|
||||
FIRST, LAST;
|
||||
}
|
||||
|
||||
private final Expression child;
|
||||
private final OrderDirection direction;
|
||||
private final NullsPosition nulls;
|
||||
|
||||
public Order(Location location, Expression child, OrderDirection direction) {
|
||||
public Order(Location location, Expression child, OrderDirection direction, NullsPosition nulls) {
|
||||
super(location, singletonList(child));
|
||||
this.child = child;
|
||||
this.direction = direction;
|
||||
this.nulls = nulls == null ? (direction == OrderDirection.DESC ? NullsPosition.FIRST : NullsPosition.LAST) : nulls;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<Order> info() {
|
||||
return NodeInfo.create(this, Order::new, child, direction);
|
||||
return NodeInfo.create(this, Order::new, child, direction, nulls);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -49,7 +55,7 @@ public class Order extends Expression {
|
||||
if (newChildren.size() != 1) {
|
||||
throw new IllegalArgumentException("expected [1] child but received [" + newChildren.size() + "]");
|
||||
}
|
||||
return new Order(location(), newChildren.get(0), direction);
|
||||
return new Order(location(), newChildren.get(0), direction, nulls);
|
||||
}
|
||||
|
||||
public Expression child() {
|
||||
@ -60,6 +66,10 @@ public class Order extends Expression {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public NullsPosition nullsPosition() {
|
||||
return nulls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean foldable() {
|
||||
return false;
|
||||
@ -67,7 +77,7 @@ public class Order extends Expression {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(child, direction);
|
||||
return Objects.hash(child, direction, nulls);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,6 +92,7 @@ public class Order extends Expression {
|
||||
|
||||
Order other = (Order) obj;
|
||||
return Objects.equals(direction, other.direction)
|
||||
&& Objects.equals(nulls, other.nulls)
|
||||
&& Objects.equals(child, other.child);
|
||||
}
|
||||
}
|
@ -7,10 +7,12 @@ package org.elasticsearch.xpack.sql.expression.function.scalar;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class BinaryScalarFunction extends ScalarFunction {
|
||||
|
||||
@ -53,5 +55,11 @@ public abstract class BinaryScalarFunction extends ScalarFunction {
|
||||
return asScriptFrom(leftScript, rightScript);
|
||||
}
|
||||
|
||||
protected abstract ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript);
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
return Scripts.binaryMethod(scriptMethodName(), leftScript, rightScript, dataType());
|
||||
}
|
||||
|
||||
protected String scriptMethodName() {
|
||||
return getClass().getSimpleName().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunctio
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
abstract class BaseDateTimeFunction extends UnaryScalarFunction {
|
||||
@ -60,4 +62,32 @@ abstract class BaseDateTimeFunction extends UnaryScalarFunction {
|
||||
public boolean foldable() {
|
||||
return field().foldable();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
DateTime folded = (DateTime) field().fold();
|
||||
if (folded == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return doFold(folded.getMillis(), timeZone().getID());
|
||||
}
|
||||
|
||||
protected abstract Object doFold(long millis, String tzId);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
BaseDateTimeFunction other = (BaseDateTimeFunction) obj;
|
||||
return Objects.equals(other.field(), field())
|
||||
&& Objects.equals(other.timeZone(), timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(field(), timeZone());
|
||||
}
|
||||
}
|
@ -15,13 +15,11 @@ import org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
@ -33,13 +31,8 @@ public abstract class DateTimeFunction extends BaseDateTimeFunction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
DateTime folded = (DateTime) field().fold();
|
||||
if (folded == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return dateTimeChrono(folded.getMillis(), timeZone().getID(), chronoField().name());
|
||||
protected Object doFold(long millis, String tzId) {
|
||||
return dateTimeChrono(millis, tzId, chronoField().name());
|
||||
}
|
||||
|
||||
public static Integer dateTimeChrono(long millis, String tzId, String chronoName) {
|
||||
@ -47,12 +40,17 @@ public abstract class DateTimeFunction extends BaseDateTimeFunction {
|
||||
return Integer.valueOf(time.get(ChronoField.valueOf(chronoName)));
|
||||
}
|
||||
|
||||
public static Integer dateTimeChrono(ZonedDateTime millis, String tzId, String chronoName) {
|
||||
ZonedDateTime time = millis.withZoneSameInstant(ZoneId.of(tzId));
|
||||
return Integer.valueOf(time.get(ChronoField.valueOf(chronoName)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate scriptWithField(FieldAttribute field) {
|
||||
ParamsBuilder params = paramsBuilder();
|
||||
|
||||
String template = null;
|
||||
template = formatTemplate("{sql}.dateTimeChrono(doc[{}].value.millis, {}, {})");
|
||||
template = formatTemplate("{sql}.dateTimeChrono(doc[{}].value, {}, {})");
|
||||
params.variable(field.name())
|
||||
.variable(timeZone().getID())
|
||||
.variable(chronoField().name());
|
||||
@ -79,19 +77,4 @@ public abstract class DateTimeFunction extends BaseDateTimeFunction {
|
||||
|
||||
// used for applying ranges
|
||||
public abstract String dateTimeFormat();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
DateTimeFunction other = (DateTimeFunction) obj;
|
||||
return Objects.equals(other.field(), field())
|
||||
&& Objects.equals(other.timeZone(), timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(field(), timeZone());
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ import java.util.TimeZone;
|
||||
public class DayName extends NamedDateTimeFunction {
|
||||
|
||||
public DayName(Location location, Expression field, TimeZone timeZone) {
|
||||
super(location, field, timeZone);
|
||||
super(location, field, timeZone, NameExtractor.DAY_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -30,9 +30,4 @@ public class DayName extends NamedDateTimeFunction {
|
||||
protected DayName replaceChild(Expression newChild) {
|
||||
return new DayName(location(), newChild, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NameExtractor nameExtractor() {
|
||||
return NameExtractor.DAY_NAME;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ import java.util.TimeZone;
|
||||
public class MonthName extends NamedDateTimeFunction {
|
||||
|
||||
public MonthName(Location location, Expression field, TimeZone timeZone) {
|
||||
super(location, field, timeZone);
|
||||
super(location, field, timeZone, NameExtractor.MONTH_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -30,10 +30,4 @@ public class MonthName extends NamedDateTimeFunction {
|
||||
protected MonthName replaceChild(Expression newChild) {
|
||||
return new MonthName(location(), newChild, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NameExtractor nameExtractor() {
|
||||
return NameExtractor.MONTH_NAME;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -15,10 +15,8 @@ import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static java.lang.String.format;
|
||||
@ -29,25 +27,23 @@ import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.pa
|
||||
*/
|
||||
abstract class NamedDateTimeFunction extends BaseDateTimeFunction {
|
||||
|
||||
NamedDateTimeFunction(Location location, Expression field, TimeZone timeZone) {
|
||||
private final NameExtractor nameExtractor;
|
||||
|
||||
NamedDateTimeFunction(Location location, Expression field, TimeZone timeZone, NameExtractor nameExtractor) {
|
||||
super(location, field, timeZone);
|
||||
this.nameExtractor = nameExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
DateTime folded = (DateTime) field().fold();
|
||||
if (folded == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return nameExtractor().extract(folded.getMillis(), timeZone().getID());
|
||||
protected Object doFold(long millis, String tzId) {
|
||||
return nameExtractor.extract(millis, tzId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate scriptWithField(FieldAttribute field) {
|
||||
return new ScriptTemplate(
|
||||
formatTemplate(format(Locale.ROOT, "{sql}.%s(doc[{}].value.millis, {})",
|
||||
StringUtils.underscoreToLowerCamelCase(nameExtractor().name()))),
|
||||
formatTemplate(format(Locale.ROOT, "{sql}.%s(doc[{}].value, {})",
|
||||
StringUtils.underscoreToLowerCamelCase(nameExtractor.name()))),
|
||||
paramsBuilder()
|
||||
.variable(field.name())
|
||||
.variable(timeZone().getID()).build(),
|
||||
@ -56,29 +52,11 @@ abstract class NamedDateTimeFunction extends BaseDateTimeFunction {
|
||||
|
||||
@Override
|
||||
protected final Pipe makePipe() {
|
||||
return new UnaryPipe(location(), this, Expressions.pipe(field()),
|
||||
new NamedDateTimeProcessor(nameExtractor(), timeZone()));
|
||||
return new UnaryPipe(location(), this, Expressions.pipe(field()), new NamedDateTimeProcessor(nameExtractor, timeZone()));
|
||||
}
|
||||
|
||||
protected abstract NameExtractor nameExtractor();
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return DataType.KEYWORD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
NamedDateTimeFunction other = (NamedDateTimeFunction) obj;
|
||||
return Objects.equals(other.field(), field())
|
||||
&& Objects.equals(other.timeZone(), timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(field(), timeZone());
|
||||
}
|
||||
}
|
@ -16,36 +16,35 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class NamedDateTimeProcessor extends BaseDateTimeProcessor {
|
||||
|
||||
public enum NameExtractor {
|
||||
// for the moment we'll use no specific Locale, but we might consider introducing a Locale parameter, just like the timeZone one
|
||||
DAY_NAME((Long millis, String tzId) -> {
|
||||
ZonedDateTime time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId));
|
||||
return time.format(DateTimeFormatter.ofPattern(DAY_NAME_FORMAT, Locale.ROOT));
|
||||
}),
|
||||
MONTH_NAME((Long millis, String tzId) -> {
|
||||
ZonedDateTime time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId));
|
||||
return time.format(DateTimeFormatter.ofPattern(MONTH_NAME_FORMAT, Locale.ROOT));
|
||||
});
|
||||
DAY_NAME(time -> time.format(DAY_NAME_FORMATTER)),
|
||||
MONTH_NAME(time -> time.format(MONTH_NAME_FORMATTER));
|
||||
|
||||
private final BiFunction<Long,String,String> apply;
|
||||
|
||||
NameExtractor(BiFunction<Long,String,String> apply) {
|
||||
private final Function<ZonedDateTime, String> apply;
|
||||
|
||||
NameExtractor(Function<ZonedDateTime, String> apply) {
|
||||
this.apply = apply;
|
||||
}
|
||||
|
||||
public final String extract(Long millis, String tzId) {
|
||||
return apply.apply(millis, tzId);
|
||||
return extract(ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId)), tzId);
|
||||
}
|
||||
|
||||
public final String extract(ZonedDateTime millis, String tzId) {
|
||||
return apply.apply(millis.withZoneSameInstant(ZoneId.of(tzId)));
|
||||
}
|
||||
}
|
||||
|
||||
public static final String NAME = "ndt";
|
||||
private static final String MONTH_NAME_FORMAT = "MMMM";
|
||||
private static final String DAY_NAME_FORMAT = "EEEE";
|
||||
|
||||
private static final DateTimeFormatter DAY_NAME_FORMATTER = DateTimeFormatter.ofPattern("EEEE", Locale.ROOT);
|
||||
private static final DateTimeFormatter MONTH_NAME_FORMATTER = DateTimeFormatter.ofPattern("MMMM", Locale.ROOT);
|
||||
|
||||
|
||||
private final NameExtractor extractor;
|
||||
|
||||
public NamedDateTimeProcessor(NameExtractor extractor, TimeZone timeZone) {
|
||||
@ -97,4 +96,4 @@ public class NamedDateTimeProcessor extends BaseDateTimeProcessor {
|
||||
public String toString() {
|
||||
return extractor.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -15,9 +15,7 @@ import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor.quarter;
|
||||
@ -25,25 +23,18 @@ import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.pa
|
||||
|
||||
public class Quarter extends BaseDateTimeFunction {
|
||||
|
||||
protected static final String QUARTER_FORMAT = "q";
|
||||
|
||||
public Quarter(Location location, Expression field, TimeZone timeZone) {
|
||||
super(location, field, timeZone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
DateTime folded = (DateTime) field().fold();
|
||||
if (folded == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return quarter(folded.getMillis(), timeZone().getID());
|
||||
protected Object doFold(long millis, String tzId) {
|
||||
return quarter(millis, tzId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate scriptWithField(FieldAttribute field) {
|
||||
return new ScriptTemplate(formatTemplate("{sql}.quarter(doc[{}].value.millis, {})"),
|
||||
return new ScriptTemplate(formatTemplate("{sql}.quarter(doc[{}].value, {})"),
|
||||
paramsBuilder()
|
||||
.variable(field.name())
|
||||
.variable(timeZone().getID())
|
||||
@ -70,19 +61,4 @@ public class Quarter extends BaseDateTimeFunction {
|
||||
public DataType dataType() {
|
||||
return DataType.INTEGER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
BaseDateTimeFunction other = (BaseDateTimeFunction) obj;
|
||||
return Objects.equals(other.field(), field())
|
||||
&& Objects.equals(other.timeZone(), timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(field(), timeZone());
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ public class QuarterProcessor extends BaseDateTimeProcessor {
|
||||
}
|
||||
|
||||
public static final String NAME = "q";
|
||||
private static final DateTimeFormatter QUARTER_FORMAT = DateTimeFormatter.ofPattern("q", Locale.ROOT);
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
@ -40,8 +41,12 @@ public class QuarterProcessor extends BaseDateTimeProcessor {
|
||||
}
|
||||
|
||||
public static Integer quarter(long millis, String tzId) {
|
||||
ZonedDateTime time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId));
|
||||
return Integer.valueOf(time.format(DateTimeFormatter.ofPattern(Quarter.QUARTER_FORMAT, Locale.ROOT)));
|
||||
return quarter(ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId)), tzId);
|
||||
}
|
||||
|
||||
public static Integer quarter(ZonedDateTime zdt, String tzId) {
|
||||
ZonedDateTime time = zdt.withZoneSameInstant(ZoneId.of(tzId));
|
||||
return Integer.valueOf(time.format(QUARTER_FORMAT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,8 +21,7 @@ public class BinaryMathPipe extends BinaryPipe {
|
||||
|
||||
private final BinaryMathOperation operation;
|
||||
|
||||
public BinaryMathPipe(Location location, Expression expression, Pipe left,
|
||||
Pipe right, BinaryMathOperation operation) {
|
||||
public BinaryMathPipe(Location location, Expression expression, Pipe left, Pipe right, BinaryMathOperation operation) {
|
||||
super(location, expression, left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
@ -6,10 +6,10 @@
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.math;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.FunctionalBinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Arithmetics;
|
||||
|
||||
@ -19,7 +19,7 @@ import java.util.function.BiFunction;
|
||||
/**
|
||||
* Binary math operations. Sister class to {@link MathOperation}.
|
||||
*/
|
||||
public class BinaryMathProcessor extends BinaryNumericProcessor<BinaryMathOperation> {
|
||||
public class BinaryMathProcessor extends FunctionalBinaryProcessor<Number, Number, Number, BinaryMathOperation> {
|
||||
|
||||
public enum BinaryMathOperation implements BiFunction<Number, Number, Number> {
|
||||
|
||||
@ -27,12 +27,6 @@ public class BinaryMathProcessor extends BinaryNumericProcessor<BinaryMathOperat
|
||||
MOD(Arithmetics::mod),
|
||||
POWER((l, r) -> Math.pow(l.doubleValue(), r.doubleValue())),
|
||||
ROUND((l, r) -> {
|
||||
if (l == null) {
|
||||
return null;
|
||||
}
|
||||
if (r == null) {
|
||||
return l;
|
||||
}
|
||||
if (r instanceof Float || r instanceof Double) {
|
||||
throw new SqlIllegalArgumentException("An integer number is required; received [{}] as second parameter", r);
|
||||
}
|
||||
@ -43,12 +37,6 @@ public class BinaryMathProcessor extends BinaryNumericProcessor<BinaryMathOperat
|
||||
return Math.round(Math.abs(middleResult)) / tenAtScale * sign;
|
||||
}),
|
||||
TRUNCATE((l, r) -> {
|
||||
if (l == null) {
|
||||
return null;
|
||||
}
|
||||
if (r == null) {
|
||||
return l;
|
||||
}
|
||||
if (r instanceof Float || r instanceof Double) {
|
||||
throw new SqlIllegalArgumentException("An integer number is required; received [{}] as second parameter", r);
|
||||
}
|
||||
@ -66,6 +54,9 @@ public class BinaryMathProcessor extends BinaryNumericProcessor<BinaryMathOperat
|
||||
|
||||
@Override
|
||||
public final Number apply(Number left, Number right) {
|
||||
if (left == null || right == null) {
|
||||
return null;
|
||||
}
|
||||
return process.apply(left, right);
|
||||
}
|
||||
}
|
||||
@ -80,13 +71,15 @@ public class BinaryMathProcessor extends BinaryNumericProcessor<BinaryMathOperat
|
||||
super(in, i -> i.readEnum(BinaryMathOperation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {
|
||||
out.writeEnum(operation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkParameter(Object param) {
|
||||
if (!(param instanceof Number)) {
|
||||
throw new SqlIllegalArgumentException("A number is required; received {}", param);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,16 +10,11 @@ import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.BinaryScalarFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
public abstract class BinaryNumericFunction extends BinaryScalarFunction {
|
||||
|
||||
private final BinaryMathOperation operation;
|
||||
@ -51,7 +46,7 @@ public abstract class BinaryNumericFunction extends BinaryScalarFunction {
|
||||
protected TypeResolution resolveInputType(DataType inputType) {
|
||||
return inputType.isNumeric() ?
|
||||
TypeResolution.TYPE_RESOLVED :
|
||||
new TypeResolution("'%s' requires a numeric type, received %s", mathFunction(), inputType.esType);
|
||||
new TypeResolution("'%s' requires a numeric type, received %s", scriptMethodName(), inputType.esType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,18 +59,6 @@ public abstract class BinaryNumericFunction extends BinaryScalarFunction {
|
||||
return new BinaryMathPipe(location(), this, Expressions.pipe(left()), Expressions.pipe(right()), operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
return new ScriptTemplate(format(Locale.ROOT, "Math.%s(%s,%s)", mathFunction(), leftScript.template(), rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params()).script(rightScript.params())
|
||||
.build(), dataType());
|
||||
}
|
||||
|
||||
protected String mathFunction() {
|
||||
return getClass().getSimpleName().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(left(), right(), operation);
|
||||
|
@ -1,76 +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.expression.function.scalar.math;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.BinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public abstract class BinaryNumericProcessor<O extends Enum<?> & BiFunction<Number, Number, Number>> extends BinaryProcessor {
|
||||
|
||||
private final O operation;
|
||||
|
||||
protected BinaryNumericProcessor(Processor left, Processor right, O operation) {
|
||||
super(left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
protected BinaryNumericProcessor(StreamInput in, Reader<O> reader) throws IOException {
|
||||
super(in);
|
||||
operation = reader.read(in);
|
||||
}
|
||||
|
||||
protected O operation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
if (left == null || right == null) {
|
||||
return null;
|
||||
}
|
||||
if (!(left instanceof Number)) {
|
||||
throw new SqlIllegalArgumentException("A number is required; received {}", left);
|
||||
}
|
||||
if (!(right instanceof Number)) {
|
||||
throw new SqlIllegalArgumentException("A number is required; received {}", right);
|
||||
}
|
||||
|
||||
return operation.apply((Number) left, (Number) right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BinaryNumericProcessor<?> other = (BinaryNumericProcessor<?>) obj;
|
||||
return Objects.equals(operation, other.operation)
|
||||
&& Objects.equals(left(), other.left())
|
||||
&& Objects.equals(right(), other.right());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.ROOT, "(%s %s %s)", left(), operation, right());
|
||||
}
|
||||
}
|
@ -10,10 +10,6 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* <a href="https://en.wikipedia.org/wiki/Trigonometric_functions#Cosecant,_secant,_and_cotangent">Cotangent</a>
|
||||
* function.
|
||||
@ -33,12 +29,6 @@ public class Cot extends MathFunction {
|
||||
return new Cot(location(), newChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String processScript(String template) {
|
||||
// FIXME: needs to be null aware
|
||||
return super.processScript(format(Locale.ROOT, "1.0 / Math.tan(%s)", template));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MathOperation operation() {
|
||||
return MathOperation.COT;
|
||||
|
@ -29,11 +29,6 @@ public class Degrees extends MathFunction {
|
||||
return new Degrees(location(), newChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String mathFunction() {
|
||||
return "toDegrees";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MathOperation operation() {
|
||||
return MathOperation.DEGREES;
|
||||
|
@ -41,7 +41,7 @@ public abstract class MathFunction extends UnaryScalarFunction {
|
||||
|
||||
@Override
|
||||
public String processScript(String template) {
|
||||
return super.processScript(format(Locale.ROOT, "Math.%s(%s)", mathFunction(), template));
|
||||
return super.processScript(format(Locale.ROOT, "{sql}.%s(%s)", mathFunction(), template));
|
||||
}
|
||||
|
||||
protected String mathFunction() {
|
||||
|
@ -22,14 +22,14 @@ public class MathProcessor implements Processor {
|
||||
public enum MathOperation {
|
||||
ABS((Object l) -> {
|
||||
if (l instanceof Float) {
|
||||
return Math.abs(((Float) l).floatValue());
|
||||
return Double.valueOf(Math.abs(((Float) l).floatValue()));
|
||||
}
|
||||
if (l instanceof Double) {
|
||||
return Math.abs(((Double) l).doubleValue());
|
||||
}
|
||||
long lo = ((Number) l).longValue();
|
||||
//handles the corner-case of Long.MIN_VALUE
|
||||
return lo >= 0 ? lo : lo == Long.MIN_VALUE ? Long.MAX_VALUE : -lo;
|
||||
return lo >= 0 ? lo : lo == Long.MIN_VALUE ? Double.valueOf(Long.MAX_VALUE) : -lo;
|
||||
}),
|
||||
|
||||
ACOS(Math::acos),
|
||||
@ -52,15 +52,15 @@ public class MathProcessor implements Processor {
|
||||
RANDOM((Object l) -> l != null ?
|
||||
new Random(((Number) l).longValue()).nextDouble() :
|
||||
Randomness.get().nextDouble(), true),
|
||||
SIGN((DoubleFunction<Object>) Math::signum),
|
||||
SIGN((DoubleFunction<Double>) Math::signum),
|
||||
SIN(Math::sin),
|
||||
SINH(Math::sinh),
|
||||
SQRT(Math::sqrt),
|
||||
TAN(Math::tan);
|
||||
|
||||
private final Function<Object, Object> apply;
|
||||
private final Function<Object, Double> apply;
|
||||
|
||||
MathOperation(Function<Object, Object> apply) {
|
||||
MathOperation(Function<Object, Double> apply) {
|
||||
this(apply, false);
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ public class MathProcessor implements Processor {
|
||||
* If true, nulls are passed through, otherwise the function is short-circuited
|
||||
* and null returned.
|
||||
*/
|
||||
MathOperation(Function<Object, Object> apply, boolean nullAware) {
|
||||
MathOperation(Function<Object, Double> apply, boolean nullAware) {
|
||||
if (nullAware) {
|
||||
this.apply = apply;
|
||||
} else {
|
||||
@ -77,7 +77,7 @@ public class MathProcessor implements Processor {
|
||||
}
|
||||
}
|
||||
|
||||
MathOperation(DoubleFunction<Object> apply) {
|
||||
MathOperation(DoubleFunction<Double> apply) {
|
||||
this.apply = (Object l) -> l == null ? null : apply.apply(((Number) l).doubleValue());
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ public class MathProcessor implements Processor {
|
||||
this.apply = l -> supplier.get();
|
||||
}
|
||||
|
||||
public final Object apply(Object l) {
|
||||
public final Double apply(Object l) {
|
||||
return apply.apply(l);
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,4 @@ public class Power extends BinaryNumericFunction {
|
||||
protected Power replaceChildren(Expression newLeft, Expression newRight) {
|
||||
return new Power(location(), newLeft, newRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String mathFunction() {
|
||||
return "pow";
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,6 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* Returns a random double (using the given seed).
|
||||
*/
|
||||
@ -33,13 +29,6 @@ public class Random extends MathFunction {
|
||||
return new Random(location(), newChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String processScript(String template) {
|
||||
//TODO: Painless script uses Random since Randomness is not whitelisted
|
||||
return super.processScript(
|
||||
format(Locale.ROOT, "%s != null ? new Random((long) %s).nextDouble() : Math.random()", template, template));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MathOperation operation() {
|
||||
return MathOperation.RANDOM;
|
||||
|
@ -8,16 +8,10 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.math;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.Literal;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
/**
|
||||
* Function that takes two parameters: one is the field/value itself, the other is a non-floating point numeric
|
||||
* which indicates how the rounding should behave. If positive, it will round the number till that parameter
|
||||
@ -39,17 +33,6 @@ public class Round extends BinaryNumericFunction {
|
||||
protected Round replaceChildren(Expression newLeft, Expression newRight) {
|
||||
return new Round(location(), newLeft, newRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
return new ScriptTemplate(format(Locale.ROOT, formatTemplate("{sql}.%s(%s,%s)"),
|
||||
mathFunction(),
|
||||
leftScript.template(),
|
||||
rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params()).script(rightScript.params())
|
||||
.build(), dataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
|
@ -8,16 +8,10 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.math;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.Literal;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
/**
|
||||
* Function that takes two parameters: one is the field/value itself, the other is a non-floating point numeric
|
||||
* which indicates how the truncation should behave. If positive, it will truncate the number till that
|
||||
@ -40,17 +34,6 @@ public class Truncate extends BinaryNumericFunction {
|
||||
return new Truncate(location(), newLeft, newRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
return new ScriptTemplate(format(Locale.ROOT, formatTemplate("{sql}.%s(%s,%s)"),
|
||||
mathFunction(),
|
||||
leftScript.template(),
|
||||
rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params()).script(rightScript.params())
|
||||
.build(), dataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return left().dataType();
|
||||
|
@ -16,7 +16,6 @@ import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
/**
|
||||
@ -59,17 +58,10 @@ public abstract class BinaryStringFunction<T,R> extends BinaryScalarFunction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
// basically, transform the script to InternalSqlScriptUtils.[function_name](function_or_field1, function_or_field2)
|
||||
return new ScriptTemplate(format(Locale.ROOT, formatTemplate("{sql}.%s(%s,%s)"),
|
||||
operation().toString().toLowerCase(Locale.ROOT),
|
||||
leftScript.template(),
|
||||
rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params()).script(rightScript.params())
|
||||
.build(), dataType());
|
||||
protected String scriptMethodName() {
|
||||
return operation().toString().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ScriptTemplate scriptWithField(FieldAttribute field) {
|
||||
return new ScriptTemplate(processScript("doc[{}].value"),
|
||||
|
@ -21,8 +21,8 @@ public class BinaryStringNumericPipe extends BinaryPipe {
|
||||
|
||||
private final BinaryStringNumericOperation operation;
|
||||
|
||||
public BinaryStringNumericPipe(Location location, Expression expression, Pipe left,
|
||||
Pipe right, BinaryStringNumericOperation operation) {
|
||||
public BinaryStringNumericPipe(Location location, Expression expression, Pipe left, Pipe right,
|
||||
BinaryStringNumericOperation operation) {
|
||||
super(location, expression, left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
@ -6,9 +6,9 @@
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.string;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringNumericProcessor.BinaryStringNumericOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.FunctionalBinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -18,32 +18,28 @@ import java.util.function.BiFunction;
|
||||
* Processor class covering string manipulating functions that have the first parameter as string,
|
||||
* second parameter as numeric and a string result.
|
||||
*/
|
||||
public class BinaryStringNumericProcessor extends BinaryStringProcessor<BinaryStringNumericOperation, Number, String> {
|
||||
public class BinaryStringNumericProcessor extends FunctionalBinaryProcessor<String, Number, String, BinaryStringNumericOperation> {
|
||||
|
||||
public static final String NAME = "sn";
|
||||
|
||||
public BinaryStringNumericProcessor(StreamInput in) throws IOException {
|
||||
super(in, i -> i.readEnum(BinaryStringNumericOperation.class));
|
||||
}
|
||||
|
||||
public BinaryStringNumericProcessor(Processor left, Processor right, BinaryStringNumericOperation operation) {
|
||||
super(left, right, operation);
|
||||
}
|
||||
|
||||
public enum BinaryStringNumericOperation implements BiFunction<String, Number, String> {
|
||||
LEFT((s,c) -> {
|
||||
int i = c.intValue();
|
||||
if (i < 0) return "";
|
||||
if (i < 0) {
|
||||
return "";
|
||||
}
|
||||
return i > s.length() ? s : s.substring(0, i);
|
||||
}),
|
||||
RIGHT((s,c) -> {
|
||||
int i = c.intValue();
|
||||
if (i < 0) return "";
|
||||
if (i < 0) {
|
||||
return "";
|
||||
}
|
||||
return i > s.length() ? s : s.substring(s.length() - i);
|
||||
}),
|
||||
REPEAT((s,c) -> {
|
||||
int i = c.intValue();
|
||||
if (i <= 0) return null;
|
||||
if (i <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(s.length() * i);
|
||||
for (int j = 0; j < i; j++) {
|
||||
@ -57,31 +53,24 @@ public class BinaryStringNumericProcessor extends BinaryStringProcessor<BinarySt
|
||||
}
|
||||
|
||||
private final BiFunction<String, Number, String> op;
|
||||
|
||||
|
||||
@Override
|
||||
public String apply(String stringExp, Number count) {
|
||||
if (stringExp == null || count == null) {
|
||||
return null;
|
||||
}
|
||||
return op.apply(stringExp, count);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {
|
||||
out.writeEnum(operation());
|
||||
public static final String NAME = "sn";
|
||||
|
||||
public BinaryStringNumericProcessor(Processor left, Processor right, BinaryStringNumericOperation operation) {
|
||||
super(left, right, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
if (left == null || right == null) {
|
||||
return null;
|
||||
}
|
||||
if (!(left instanceof String || left instanceof Character)) {
|
||||
throw new SqlIllegalArgumentException("A string/char is required; received [{}]", left);
|
||||
}
|
||||
if (!(right instanceof Number)) {
|
||||
throw new SqlIllegalArgumentException("A number is required; received [{}]", right);
|
||||
}
|
||||
|
||||
return operation().apply(left instanceof Character ? left.toString() : (String) left, (Number) right);
|
||||
public BinaryStringNumericProcessor(StreamInput in) throws IOException {
|
||||
super(in, i -> i.readEnum(BinaryStringNumericOperation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,4 +78,15 @@ public class BinaryStringNumericProcessor extends BinaryStringProcessor<BinarySt
|
||||
return NAME;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
if (!(left instanceof String || left instanceof Character)) {
|
||||
throw new SqlIllegalArgumentException("A string/char is required; received [{}]", left);
|
||||
}
|
||||
if (!(right instanceof Number)) {
|
||||
throw new SqlIllegalArgumentException("A number is required; received [{}]", right);
|
||||
}
|
||||
|
||||
return super.doProcess(left.toString(), right);
|
||||
}
|
||||
}
|
@ -1,59 +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.expression.function.scalar.string;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.BinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public abstract class BinaryStringProcessor<O extends Enum<?> & BiFunction<String, T, R>, T, R> extends BinaryProcessor {
|
||||
|
||||
private final O operation;
|
||||
|
||||
public BinaryStringProcessor(Processor left, Processor right, O operation) {
|
||||
super(left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public BinaryStringProcessor(StreamInput in, Reader<O> reader) throws IOException {
|
||||
super(in);
|
||||
operation = reader.read(in);
|
||||
}
|
||||
|
||||
protected O operation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BinaryStringProcessor<?,?,?> other = (BinaryStringProcessor<?,?,?>) obj;
|
||||
return Objects.equals(operation, other.operation)
|
||||
&& Objects.equals(left(), other.left())
|
||||
&& Objects.equals(right(), other.right());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return operation.toString();
|
||||
}
|
||||
}
|
@ -21,8 +21,7 @@ public class BinaryStringStringPipe extends BinaryPipe {
|
||||
|
||||
private final BinaryStringStringOperation operation;
|
||||
|
||||
public BinaryStringStringPipe(Location location, Expression expression, Pipe left,
|
||||
Pipe right, BinaryStringStringOperation operation) {
|
||||
public BinaryStringStringPipe(Location location, Expression expression, Pipe left, Pipe right, BinaryStringStringOperation operation) {
|
||||
super(location, expression, left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
@ -6,9 +6,9 @@
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.string;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringStringProcessor.BinaryStringStringOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.FunctionalBinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -17,21 +17,10 @@ import java.util.function.BiFunction;
|
||||
/**
|
||||
* Processor class covering string manipulating functions that have two string parameters and a numeric result.
|
||||
*/
|
||||
public class BinaryStringStringProcessor extends BinaryStringProcessor<BinaryStringStringOperation, String, Number> {
|
||||
public class BinaryStringStringProcessor extends FunctionalBinaryProcessor<String, String, Number, BinaryStringStringOperation> {
|
||||
|
||||
public static final String NAME = "ss";
|
||||
|
||||
public BinaryStringStringProcessor(StreamInput in) throws IOException {
|
||||
super(in, i -> i.readEnum(BinaryStringStringOperation.class));
|
||||
}
|
||||
|
||||
public BinaryStringStringProcessor(Processor left, Processor right, BinaryStringStringOperation operation) {
|
||||
super(left, right, operation);
|
||||
}
|
||||
|
||||
public enum BinaryStringStringOperation implements BiFunction<String, String, Number> {
|
||||
POSITION((sub,str) -> {
|
||||
if (sub == null || str == null) return null;
|
||||
int pos = str.indexOf(sub);
|
||||
return pos < 0 ? 0 : pos+1;
|
||||
});
|
||||
@ -43,30 +32,22 @@ public class BinaryStringStringProcessor extends BinaryStringProcessor<BinaryStr
|
||||
private final BiFunction<String, String, Number> op;
|
||||
|
||||
@Override
|
||||
public Number apply(String stringExpLeft, String stringExpRight) {
|
||||
return op.apply(stringExpLeft, stringExpRight);
|
||||
public Number apply(String left, String right) {
|
||||
if (left == null || right == null) {
|
||||
return null;
|
||||
}
|
||||
return op.apply(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {
|
||||
out.writeEnum(operation());
|
||||
public static final String NAME = "ss";
|
||||
|
||||
public BinaryStringStringProcessor(StreamInput in) throws IOException {
|
||||
super(in, i -> i.readEnum(BinaryStringStringOperation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
if (left == null || right == null) {
|
||||
return null;
|
||||
}
|
||||
if (!(left instanceof String || left instanceof Character)) {
|
||||
throw new SqlIllegalArgumentException("A string/char is required; received [{}]", left);
|
||||
}
|
||||
if (!(right instanceof String || right instanceof Character)) {
|
||||
throw new SqlIllegalArgumentException("A string/char is required; received [{}]", right);
|
||||
}
|
||||
|
||||
return operation().apply(left instanceof Character ? left.toString() : (String) left,
|
||||
right instanceof Character ? right.toString() : (String) right);
|
||||
public BinaryStringStringProcessor(Processor left, Processor right, BinaryStringStringOperation operation) {
|
||||
super(left, right, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,4 +55,15 @@ public class BinaryStringStringProcessor extends BinaryStringProcessor<BinaryStr
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
if (!(left instanceof String || left instanceof Character)) {
|
||||
throw new SqlIllegalArgumentException("A string/char is required; received [{}]", left);
|
||||
}
|
||||
if (!(right instanceof String || right instanceof Character)) {
|
||||
throw new SqlIllegalArgumentException("A string/char is required; received [{}]", right);
|
||||
}
|
||||
|
||||
return super.doProcess(left.toString(), right.toString());
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,7 @@ import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.string.ConcatFunctionProcessor.doProcessInScripts;
|
||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.string.ConcatFunctionProcessor.process;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
/**
|
||||
@ -58,7 +55,7 @@ public class Concat extends BinaryScalarFunction {
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return doProcessInScripts(left().fold(), right().fold());
|
||||
return process(left().fold(), right().fold());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,18 +68,6 @@ public class Concat extends BinaryScalarFunction {
|
||||
return NodeInfo.create(this, Concat::new, left(), right());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
// basically, transform the script to InternalSqlScriptUtils.[function_name](function_or_field1, function_or_field2)
|
||||
return new ScriptTemplate(format(Locale.ROOT, formatTemplate("{sql}.%s(%s,%s)"),
|
||||
"concat",
|
||||
leftScript.template(),
|
||||
rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params()).script(rightScript.params())
|
||||
.build(), dataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate scriptWithField(FieldAttribute field) {
|
||||
return new ScriptTemplate(processScript("doc[{}].value"),
|
||||
|
@ -15,8 +15,7 @@ import java.util.Objects;
|
||||
|
||||
public class ConcatFunctionPipe extends BinaryPipe {
|
||||
|
||||
public ConcatFunctionPipe(Location location, Expression expression, Pipe left,
|
||||
Pipe right) {
|
||||
public ConcatFunctionPipe(Location location, Expression expression, Pipe left, Pipe right) {
|
||||
super(location, expression, left, right);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.BinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
@ -27,14 +28,26 @@ public class ConcatFunctionProcessor extends BinaryProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doProcess(Object source1, Object source2) {
|
||||
return doProcessInScripts(source1, source2);
|
||||
public Object process(Object input) {
|
||||
Object l = left().process(input);
|
||||
checkParameter(l);
|
||||
Object r = right().process(input);
|
||||
checkParameter(r);
|
||||
return doProcess(l, r);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
return process(left, right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in Painless scripting
|
||||
*/
|
||||
public static Object doProcessInScripts(Object source1, Object source2) {
|
||||
public static Object process(Object source1, Object source2) {
|
||||
if (source1 == null && source2 == null) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
if (source1 == null) {
|
||||
return source2;
|
||||
}
|
||||
@ -79,4 +92,4 @@ public class ConcatFunctionProcessor extends BinaryProcessor {
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {
|
||||
}
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ public class LocateFunctionProcessor implements Processor {
|
||||
return doProcess(pattern().process(input), source().process(input), start() == null ? null : start().process(input));
|
||||
}
|
||||
|
||||
public static Object doProcess(Object pattern, Object source, Object start) {
|
||||
public static Integer doProcess(Object pattern, Object source, Object start) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
@ -63,9 +63,9 @@ public class LocateFunctionProcessor implements Processor {
|
||||
String stringSource = source instanceof Character ? source.toString() : (String) source;
|
||||
String stringPattern = pattern instanceof Character ? pattern.toString() : (String) pattern;
|
||||
|
||||
return 1 + (start != null ?
|
||||
return Integer.valueOf(1 + (start != null ?
|
||||
stringSource.indexOf(stringPattern, ((Number) start).intValue() - 1)
|
||||
: stringSource.indexOf(stringPattern));
|
||||
: stringSource.indexOf(stringPattern)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,24 +75,7 @@ public class StringProcessor implements Processor {
|
||||
}
|
||||
|
||||
StringOperation(NumericFunction<Object> apply) {
|
||||
this.apply = l -> l == null ? null : apply.apply((l));
|
||||
}
|
||||
|
||||
StringOperation(Function<Object, Object> apply) {
|
||||
this(apply, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for nulls around the given function.
|
||||
* If true, nulls are passed through, otherwise the function is short-circuited
|
||||
* and null returned.
|
||||
*/
|
||||
StringOperation(Function<Object, Object> apply, boolean nullAware) {
|
||||
if (nullAware) {
|
||||
this.apply = apply;
|
||||
} else {
|
||||
this.apply = l -> l == null ? null : apply.apply(l);
|
||||
}
|
||||
this.apply = l -> l == null ? null : apply.apply(l);
|
||||
}
|
||||
|
||||
public final Object apply(Object l) {
|
||||
|
@ -5,10 +5,14 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.whitelist;
|
||||
|
||||
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
||||
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringNumericProcessor.BinaryStringNumericOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringStringProcessor.BinaryStringStringOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ConcatFunctionProcessor;
|
||||
@ -17,6 +21,14 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.string.LocateFunct
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ReplaceFunctionProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor.StringOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.SubstringFunctionProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.regex.RegexProcessor.RegexOperation;
|
||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Whitelisted class for SQL scripts.
|
||||
@ -27,30 +39,244 @@ public final class InternalSqlScriptUtils {
|
||||
|
||||
private InternalSqlScriptUtils() {}
|
||||
|
||||
public static Integer dateTimeChrono(long millis, String tzId, String chronoName) {
|
||||
return DateTimeFunction.dateTimeChrono(millis, tzId, chronoName);
|
||||
//
|
||||
// Utilities
|
||||
//
|
||||
|
||||
// safe missing mapping/value extractor
|
||||
public static <T> Object docValue(Map<String, ScriptDocValues<T>> doc, String fieldName) {
|
||||
if (doc.containsKey(fieldName)) {
|
||||
ScriptDocValues<T> docValues = doc.get(fieldName);
|
||||
if (docValues.size() > 0) {
|
||||
return docValues.get(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String dayName(long millis, String tzId) {
|
||||
return NameExtractor.DAY_NAME.extract(millis, tzId);
|
||||
public static boolean nullSafeFilter(Boolean filter) {
|
||||
return filter == null ? false : filter.booleanValue();
|
||||
}
|
||||
|
||||
public static double nullSafeSortNumeric(Number sort) {
|
||||
return sort == null ? 0.0d : sort.doubleValue();
|
||||
}
|
||||
|
||||
public static String nullSafeSortString(Object sort) {
|
||||
return sort == null ? StringUtils.EMPTY : sort.toString();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Operators
|
||||
//
|
||||
|
||||
//
|
||||
// Logical
|
||||
//
|
||||
public static Boolean eq(Object left, Object right) {
|
||||
return BinaryComparisonOperation.EQ.apply(left, right);
|
||||
}
|
||||
|
||||
public static Boolean lt(Object left, Object right) {
|
||||
return BinaryComparisonOperation.LT.apply(left, right);
|
||||
}
|
||||
|
||||
public static String monthName(long millis, String tzId) {
|
||||
return NameExtractor.MONTH_NAME.extract(millis, tzId);
|
||||
public static Boolean lte(Object left, Object right) {
|
||||
return BinaryComparisonOperation.LTE.apply(left, right);
|
||||
}
|
||||
|
||||
public static Boolean gt(Object left, Object right) {
|
||||
return BinaryComparisonOperation.GT.apply(left, right);
|
||||
}
|
||||
|
||||
public static Boolean gte(Object left, Object right) {
|
||||
return BinaryComparisonOperation.GTE.apply(left, right);
|
||||
}
|
||||
|
||||
public static Boolean and(Boolean left, Boolean right) {
|
||||
return BinaryLogicOperation.AND.apply(left, right);
|
||||
}
|
||||
|
||||
public static Integer quarter(long millis, String tzId) {
|
||||
return QuarterProcessor.quarter(millis, tzId);
|
||||
public static Boolean or(Boolean left, Boolean right) {
|
||||
return BinaryLogicOperation.OR.apply(left, right);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Regex
|
||||
//
|
||||
public static Boolean regex(String value, String pattern) {
|
||||
return RegexOperation.match(value, pattern);
|
||||
}
|
||||
|
||||
//
|
||||
// Math
|
||||
//
|
||||
public static Number add(Number left, Number right) {
|
||||
return BinaryArithmeticOperation.ADD.apply(left, right);
|
||||
}
|
||||
|
||||
public static Number sub(Number left, Number right) {
|
||||
return BinaryArithmeticOperation.SUB.apply(left, right);
|
||||
}
|
||||
|
||||
public static Number mul(Number left, Number right) {
|
||||
return BinaryArithmeticOperation.MUL.apply(left, right);
|
||||
}
|
||||
|
||||
public static Number div(Number left, Number right) {
|
||||
return BinaryArithmeticOperation.DIV.apply(left, right);
|
||||
}
|
||||
|
||||
public static Number mod(Number left, Number right) {
|
||||
return BinaryArithmeticOperation.MOD.apply(left, right);
|
||||
}
|
||||
|
||||
public static Number round(Number v, Number s) {
|
||||
return BinaryMathOperation.ROUND.apply(v, s);
|
||||
}
|
||||
|
||||
|
||||
public static Number truncate(Number v, Number s) {
|
||||
return BinaryMathOperation.TRUNCATE.apply(v, s);
|
||||
}
|
||||
|
||||
public static Double abs(Number value) {
|
||||
return MathOperation.ABS.apply(value);
|
||||
}
|
||||
|
||||
public static Double acos(Number value) {
|
||||
return MathOperation.ACOS.apply(value);
|
||||
}
|
||||
|
||||
public static Double asin(Number value) {
|
||||
return MathOperation.ASIN.apply(value);
|
||||
}
|
||||
|
||||
public static Double atan(Number value) {
|
||||
return MathOperation.ATAN.apply(value);
|
||||
}
|
||||
|
||||
public static Double cbrt(Number value) {
|
||||
return MathOperation.CBRT.apply(value);
|
||||
}
|
||||
|
||||
public static Double ceil(Number value) {
|
||||
return MathOperation.CEIL.apply(value);
|
||||
}
|
||||
|
||||
public static Double cos(Number value) {
|
||||
return MathOperation.COS.apply(value);
|
||||
}
|
||||
|
||||
public static Double cosh(Number value) {
|
||||
return MathOperation.COSH.apply(value);
|
||||
}
|
||||
|
||||
public static Double cot(Number value) {
|
||||
return MathOperation.COT.apply(value);
|
||||
}
|
||||
|
||||
public static Double degrees(Number value) {
|
||||
return MathOperation.DEGREES.apply(value);
|
||||
}
|
||||
|
||||
public static Double e(Number value) {
|
||||
return MathOperation.E.apply(value);
|
||||
}
|
||||
|
||||
public static Double exp(Number value) {
|
||||
return MathOperation.EXP.apply(value);
|
||||
}
|
||||
|
||||
public static Double expm1(Number value) {
|
||||
return MathOperation.EXPM1.apply(value);
|
||||
}
|
||||
|
||||
public static Double floor(Number value) {
|
||||
return MathOperation.FLOOR.apply(value);
|
||||
}
|
||||
|
||||
public static Double log(Number value) {
|
||||
return MathOperation.LOG.apply(value);
|
||||
}
|
||||
|
||||
public static Double log10(Number value) {
|
||||
return MathOperation.LOG10.apply(value);
|
||||
}
|
||||
|
||||
public static Double pi(Number value) {
|
||||
return MathOperation.PI.apply(value);
|
||||
}
|
||||
|
||||
public static Double radians(Number value) {
|
||||
return MathOperation.RADIANS.apply(value);
|
||||
}
|
||||
|
||||
public static Double random(Number value) {
|
||||
return MathOperation.RANDOM.apply(value);
|
||||
}
|
||||
|
||||
public static Double sign(Number value) {
|
||||
return MathOperation.SIGN.apply(value);
|
||||
}
|
||||
|
||||
public static Double sin(Number value) {
|
||||
return MathOperation.SIN.apply(value);
|
||||
}
|
||||
|
||||
public static Double sinh(Number value) {
|
||||
return MathOperation.SINH.apply(value);
|
||||
}
|
||||
|
||||
public static Double sqrt(Number value) {
|
||||
return MathOperation.SQRT.apply(value);
|
||||
}
|
||||
|
||||
public static Double tan(Number value) {
|
||||
return MathOperation.TAN.apply(value);
|
||||
}
|
||||
|
||||
//
|
||||
// Date/Time functions
|
||||
//
|
||||
public static Integer dateTimeChrono(Object dateTime, String tzId, String chronoName) {
|
||||
if (dateTime == null || tzId == null || chronoName == null) {
|
||||
return null;
|
||||
}
|
||||
return DateTimeFunction.dateTimeChrono(asDateTime(dateTime), tzId, chronoName);
|
||||
}
|
||||
|
||||
public static String dayName(Object dateTime, String tzId) {
|
||||
if (dateTime == null || tzId == null) {
|
||||
return null;
|
||||
}
|
||||
return NameExtractor.DAY_NAME.extract(asDateTime(dateTime), tzId);
|
||||
}
|
||||
|
||||
public static String monthName(Object dateTime, String tzId) {
|
||||
if (dateTime == null || tzId == null) {
|
||||
return null;
|
||||
}
|
||||
return NameExtractor.MONTH_NAME.extract(asDateTime(dateTime), tzId);
|
||||
}
|
||||
|
||||
public static Integer quarter(Object dateTime, String tzId) {
|
||||
if (dateTime == null || tzId == null) {
|
||||
return null;
|
||||
}
|
||||
return QuarterProcessor.quarter(asDateTime(dateTime), tzId);
|
||||
}
|
||||
|
||||
private static ZonedDateTime asDateTime(Object dateTime) {
|
||||
if (dateTime instanceof JodaCompatibleZonedDateTime) {
|
||||
return ((JodaCompatibleZonedDateTime) dateTime).getZonedDateTime();
|
||||
}
|
||||
throw new SqlIllegalArgumentException("Invalid date encountered [{}]", dateTime);
|
||||
}
|
||||
|
||||
//
|
||||
// String functions
|
||||
//
|
||||
public static Integer ascii(String s) {
|
||||
return (Integer) StringOperation.ASCII.apply(s);
|
||||
}
|
||||
@ -58,43 +284,43 @@ public final class InternalSqlScriptUtils {
|
||||
public static Integer bitLength(String s) {
|
||||
return (Integer) StringOperation.BIT_LENGTH.apply(s);
|
||||
}
|
||||
|
||||
|
||||
public static String character(Number n) {
|
||||
return (String) StringOperation.CHAR.apply(n);
|
||||
}
|
||||
|
||||
|
||||
public static Integer charLength(String s) {
|
||||
return (Integer) StringOperation.CHAR_LENGTH.apply(s);
|
||||
}
|
||||
|
||||
public static String concat(String s1, String s2) {
|
||||
return ConcatFunctionProcessor.doProcessInScripts(s1, s2).toString();
|
||||
return (String) ConcatFunctionProcessor.process(s1, s2);
|
||||
}
|
||||
|
||||
public static String insert(String s, int start, int length, String r) {
|
||||
return InsertFunctionProcessor.doProcess(s, start, length, r).toString();
|
||||
|
||||
public static String insert(String s, Number start, Number length, String r) {
|
||||
return (String) InsertFunctionProcessor.doProcess(s, start, length, r);
|
||||
}
|
||||
|
||||
|
||||
public static String lcase(String s) {
|
||||
return (String) StringOperation.LCASE.apply(s);
|
||||
}
|
||||
|
||||
public static String left(String s, int count) {
|
||||
|
||||
public static String left(String s, Number count) {
|
||||
return BinaryStringNumericOperation.LEFT.apply(s, count);
|
||||
}
|
||||
|
||||
|
||||
public static Integer length(String s) {
|
||||
return (Integer) StringOperation.LENGTH.apply(s);
|
||||
}
|
||||
|
||||
|
||||
public static Integer locate(String s1, String s2) {
|
||||
return locate(s1, s2, null);
|
||||
}
|
||||
|
||||
public static Integer locate(String s1, String s2, Integer pos) {
|
||||
return (Integer) LocateFunctionProcessor.doProcess(s1, s2, pos);
|
||||
public static Integer locate(String s1, String s2, Number pos) {
|
||||
return LocateFunctionProcessor.doProcess(s1, s2, pos);
|
||||
}
|
||||
|
||||
|
||||
public static String ltrim(String s) {
|
||||
return (String) StringOperation.LTRIM.apply(s);
|
||||
}
|
||||
@ -102,35 +328,35 @@ public final class InternalSqlScriptUtils {
|
||||
public static Integer octetLength(String s) {
|
||||
return (Integer) StringOperation.OCTET_LENGTH.apply(s);
|
||||
}
|
||||
|
||||
|
||||
public static Integer position(String s1, String s2) {
|
||||
return (Integer) BinaryStringStringOperation.POSITION.apply(s1, s2);
|
||||
}
|
||||
|
||||
public static String repeat(String s, int count) {
|
||||
public static String repeat(String s, Number count) {
|
||||
return BinaryStringNumericOperation.REPEAT.apply(s, count);
|
||||
}
|
||||
|
||||
public static String replace(String s1, String s2, String s3) {
|
||||
return ReplaceFunctionProcessor.doProcess(s1, s2, s3).toString();
|
||||
return (String) ReplaceFunctionProcessor.doProcess(s1, s2, s3);
|
||||
}
|
||||
|
||||
public static String right(String s, int count) {
|
||||
public static String right(String s, Number count) {
|
||||
return BinaryStringNumericOperation.RIGHT.apply(s, count);
|
||||
}
|
||||
|
||||
|
||||
public static String rtrim(String s) {
|
||||
return (String) StringOperation.RTRIM.apply(s);
|
||||
}
|
||||
|
||||
|
||||
public static String space(Number n) {
|
||||
return (String) StringOperation.SPACE.apply(n);
|
||||
}
|
||||
|
||||
public static String substring(String s, int start, int length) {
|
||||
return SubstringFunctionProcessor.doProcess(s, start, length).toString();
|
||||
|
||||
public static String substring(String s, Number start, Number length) {
|
||||
return (String) SubstringFunctionProcessor.doProcess(s, start, length);
|
||||
}
|
||||
|
||||
|
||||
public static String ucase(String s) {
|
||||
return (String) StringOperation.UCASE.apply(s);
|
||||
}
|
||||
|
@ -35,7 +35,26 @@ public abstract class BinaryProcessor implements Processor {
|
||||
|
||||
@Override
|
||||
public Object process(Object input) {
|
||||
return doProcess(left.process(input), right.process(input));
|
||||
Object l = left.process(input);
|
||||
if (l == null) {
|
||||
return null;
|
||||
}
|
||||
checkParameter(l);
|
||||
|
||||
Object r = right.process(input);
|
||||
if (r == null) {
|
||||
return null;
|
||||
}
|
||||
checkParameter(r);
|
||||
|
||||
return doProcess(l, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the parameter (typically for its type) if the value is not null.
|
||||
*/
|
||||
protected void checkParameter(Object param) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
protected Processor left() {
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.expression.gen.processor;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Base class for definition binary processors based on functions (for applying) defined as enums (for serialization purposes).
|
||||
*/
|
||||
public abstract class FunctionalBinaryProcessor<T, U, R, F extends Enum<F> & BiFunction<T, U, R>> extends BinaryProcessor {
|
||||
|
||||
private final F function;
|
||||
|
||||
protected FunctionalBinaryProcessor(Processor left, Processor right, F function) {
|
||||
super(left, right);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
protected FunctionalBinaryProcessor(StreamInput in, Reader<F> reader) throws IOException {
|
||||
super(in);
|
||||
this.function = reader.read(in);
|
||||
}
|
||||
|
||||
public F function() {
|
||||
return function;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {
|
||||
out.writeEnum(function());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
return function.apply((T) left, (U) right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(left(), right(), function());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FunctionalBinaryProcessor<?, ?, ?, ?> other = (FunctionalBinaryProcessor<?, ?, ?, ?>) obj;
|
||||
return Objects.equals(function(), other.function())
|
||||
&& Objects.equals(left(), other.left())
|
||||
&& Objects.equals(right(), other.right());
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@ import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunctionAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalSqlScriptUtils;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
@ -75,6 +74,6 @@ public interface ScriptWeaver {
|
||||
}
|
||||
|
||||
default String formatTemplate(String template) {
|
||||
return template.replace("{sql}", InternalSqlScriptUtils.class.getSimpleName()).replace("{}", "params.%s");
|
||||
return Scripts.formatTemplate(template);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.expression.gen.script;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalSqlScriptUtils;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
public final class Scripts {
|
||||
|
||||
private Scripts() {}
|
||||
|
||||
private static final Map<Pattern, String> FORMATTING_PATTERNS = Collections.unmodifiableMap(Stream.of(
|
||||
new SimpleEntry<>("doc[{}].value", "{sql}.docValue(doc,{})"),
|
||||
new SimpleEntry<>("{sql}", InternalSqlScriptUtils.class.getSimpleName()),
|
||||
new SimpleEntry<>("{}", "params.%s"))
|
||||
.collect(toMap(e -> Pattern.compile(e.getKey(), Pattern.LITERAL), Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new)));
|
||||
|
||||
/**
|
||||
* Expands common tokens inside the script:
|
||||
*
|
||||
* <pre>
|
||||
* {sql} -> InternalSqlScriptUtils
|
||||
* doc[{}].value -> InternalSqlScriptUtils.docValue(doc, {})
|
||||
* {} -> params.%s
|
||||
* </pre>
|
||||
*/
|
||||
public static String formatTemplate(String template) {
|
||||
for (Entry<Pattern, String> entry : FORMATTING_PATTERNS.entrySet()) {
|
||||
template = entry.getKey().matcher(template).replaceAll(entry.getValue());
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
public static ScriptTemplate nullSafeFilter(ScriptTemplate script) {
|
||||
return new ScriptTemplate(formatTemplate(
|
||||
format(Locale.ROOT, "{sql}.nullSafeFilter(%s)", script.template())),
|
||||
script.params(),
|
||||
DataType.BOOLEAN);
|
||||
}
|
||||
|
||||
public static ScriptTemplate nullSafeSort(ScriptTemplate script) {
|
||||
String methodName = script.outputType().isNumeric() ? "nullSafeSortNumeric" : "nullSafeSortString";
|
||||
return new ScriptTemplate(formatTemplate(
|
||||
format(Locale.ROOT, "{sql}.%s(%s)", methodName, script.template())),
|
||||
script.params(),
|
||||
script.outputType());
|
||||
}
|
||||
|
||||
public static ScriptTemplate and(ScriptTemplate left, ScriptTemplate right) {
|
||||
return binaryMethod("and", left, right, DataType.BOOLEAN);
|
||||
}
|
||||
|
||||
public static ScriptTemplate or(ScriptTemplate left, ScriptTemplate right) {
|
||||
return binaryMethod("or", left, right, DataType.BOOLEAN);
|
||||
}
|
||||
|
||||
public static ScriptTemplate binaryMethod(String methodName, ScriptTemplate leftScript, ScriptTemplate rightScript,
|
||||
DataType dataType) {
|
||||
return new ScriptTemplate(format(Locale.ROOT, formatTemplate("{sql}.%s(%s,%s)"),
|
||||
methodName,
|
||||
leftScript.template(),
|
||||
rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params())
|
||||
.script(rightScript.params())
|
||||
.build(),
|
||||
dataType);
|
||||
}
|
||||
}
|
@ -13,19 +13,19 @@ import org.elasticsearch.xpack.sql.type.DataType;
|
||||
* Operator is a specialized binary predicate where both sides have the compatible types
|
||||
* (it's up to the analyzer to do any conversion if needed).
|
||||
*/
|
||||
public abstract class BinaryOperator extends BinaryPredicate {
|
||||
public abstract class BinaryOperator<T, U, R, F extends PredicateBiFunction<T, U, R>> extends BinaryPredicate<T, U, R, F> {
|
||||
|
||||
public interface Negateable {
|
||||
BinaryOperator negate();
|
||||
BinaryOperator<?, ?, ?, ?> negate();
|
||||
}
|
||||
|
||||
protected BinaryOperator(Location location, Expression left, Expression right, String symbol) {
|
||||
super(location, left, right, symbol);
|
||||
protected BinaryOperator(Location location, Expression left, Expression right, F function) {
|
||||
super(location, left, right, function);
|
||||
}
|
||||
|
||||
protected abstract TypeResolution resolveInputType(DataType inputType);
|
||||
|
||||
public abstract BinaryOperator swapLeftAndRight();
|
||||
public abstract BinaryOperator<T, U, R, F> swapLeftAndRight();
|
||||
|
||||
@Override
|
||||
protected TypeResolution resolveType() {
|
||||
|
@ -15,24 +15,35 @@ import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Binary operator. Operators act as _special_ functions in that they have a symbol
|
||||
* instead of a name and do not use parathensis.
|
||||
* instead of a name and do not use parentheses.
|
||||
* Further more they are not registered as the rest of the functions as are implicit
|
||||
* to the language.
|
||||
*/
|
||||
public abstract class BinaryPredicate extends BinaryScalarFunction {
|
||||
public abstract class BinaryPredicate<T, U, R, F extends PredicateBiFunction<T, U, R>> extends BinaryScalarFunction {
|
||||
|
||||
private final String symbol;
|
||||
private final String name;
|
||||
private final F function;
|
||||
|
||||
protected BinaryPredicate(Location location, Expression left, Expression right, String symbol) {
|
||||
protected BinaryPredicate(Location location, Expression left, Expression right, F function) {
|
||||
super(location, left, right);
|
||||
this.name = name(left, right, symbol);
|
||||
this.symbol = symbol;
|
||||
this.name = name(left, right, function.symbol());
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public R fold() {
|
||||
return function().apply((T) left().fold(), (U) right().fold());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String scriptMethodName() {
|
||||
return function.scriptMethodName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(left(), right());
|
||||
return Objects.hash(left(), right(), function.symbol());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -47,13 +58,26 @@ public abstract class BinaryPredicate extends BinaryScalarFunction {
|
||||
return false;
|
||||
}
|
||||
|
||||
BinaryPredicate other = (BinaryPredicate) obj;
|
||||
BinaryPredicate<?, ?, ?, ?> other = (BinaryPredicate<?, ?, ?, ?>) obj;
|
||||
|
||||
return Objects.equals(symbol, other.symbol)
|
||||
return Objects.equals(symbol(), other.symbol())
|
||||
&& Objects.equals(left(), other.left())
|
||||
&& Objects.equals(right(), other.right());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String symbol() {
|
||||
return function.symbol();
|
||||
}
|
||||
|
||||
public F function() {
|
||||
return function;
|
||||
}
|
||||
|
||||
private static String name(Expression left, Expression right, String symbol) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(Expressions.name(left));
|
||||
@ -72,13 +96,4 @@ public abstract class BinaryPredicate extends BinaryScalarFunction {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public final String symbol() {
|
||||
return symbol;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.expression.predicate;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public interface PredicateBiFunction<T, U, R> extends BiFunction<T, U, R> {
|
||||
|
||||
String name();
|
||||
|
||||
String symbol();
|
||||
|
||||
@Override
|
||||
default R apply(T t, U u) {
|
||||
if (t == null || u == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return doApply(t, u);
|
||||
}
|
||||
|
||||
R doApply(T t, U u);
|
||||
|
||||
default String scriptMethodName() {
|
||||
return name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
package org.elasticsearch.xpack.sql.expression.predicate;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Or;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -5,56 +5,56 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.predicate;
|
||||
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.Attribute;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.expression.NamedExpression;
|
||||
import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.sql.expression.Literal;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Params;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptWeaver;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicPipe;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparison;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonPipe;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.elasticsearch.xpack.sql.type.EsField;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
// BETWEEN or range - is a mix of gt(e) AND lt(e)
|
||||
public class Range extends NamedExpression implements ScriptWeaver {
|
||||
public class Range extends ScalarFunction {
|
||||
|
||||
private final String name;
|
||||
private final Expression value, lower, upper;
|
||||
private final boolean includeLower, includeUpper;
|
||||
|
||||
public Range(Location location, Expression value, Expression lower, boolean includeLower, Expression upper, boolean includeUpper) {
|
||||
this(location, null, value, lower, includeLower, upper, includeUpper);
|
||||
}
|
||||
|
||||
public Range(Location location, String name, Expression value, Expression lower, boolean includeLower, Expression upper,
|
||||
boolean includeUpper) {
|
||||
super(location, name == null ? defaultName(value, lower, upper, includeLower, includeUpper) : name,
|
||||
Arrays.asList(value, lower, upper), null);
|
||||
super(location, asList(value, lower, upper));
|
||||
|
||||
this.value = value;
|
||||
this.lower = lower;
|
||||
this.upper = upper;
|
||||
this.includeLower = includeLower;
|
||||
this.includeUpper = includeUpper;
|
||||
this.name = name(value, lower, upper, includeLower, includeUpper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<Range> info() {
|
||||
return NodeInfo.create(this, Range::new, name(), value, lower, includeLower, upper, includeUpper);
|
||||
return NodeInfo.create(this, Range::new, value, lower, includeLower, upper, includeUpper);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -130,18 +130,25 @@ public class Range extends NamedExpression implements ScriptWeaver {
|
||||
|
||||
@Override
|
||||
public ScriptTemplate asScript() {
|
||||
ScriptTemplate scriptTemplate = asScript(value);
|
||||
ScriptTemplate valueScript = asScript(value);
|
||||
ScriptTemplate lowerScript = asScript(lower);
|
||||
ScriptTemplate upperScript = asScript(upper);
|
||||
|
||||
|
||||
String template = formatTemplate(format(Locale.ROOT, "({} %s %s) && (%s %s {})",
|
||||
includeLower() ? "<=" : "<",
|
||||
scriptTemplate.template(),
|
||||
scriptTemplate.template(),
|
||||
includeUpper() ? "<=" : "<"));
|
||||
String template = formatTemplate(format(Locale.ROOT, "{sql}.and({sql}.%s(%s, %s), {sql}.%s(%s, %s))",
|
||||
includeLower() ? "gte" : "gt",
|
||||
valueScript.template(),
|
||||
lowerScript.template(),
|
||||
includeUpper() ? "lte" : "lt",
|
||||
valueScript.template(),
|
||||
upperScript.template()
|
||||
));
|
||||
|
||||
Params params = paramsBuilder().variable(Foldables.valueOf(lower))
|
||||
.script(scriptTemplate.params())
|
||||
.script(scriptTemplate.params())
|
||||
.variable(Foldables.valueOf(upper))
|
||||
Params params = paramsBuilder()
|
||||
.script(valueScript.params())
|
||||
.script(lowerScript.params())
|
||||
.script(valueScript.params())
|
||||
.script(upperScript.params())
|
||||
.build();
|
||||
|
||||
return new ScriptTemplate(template, params, DataType.BOOLEAN);
|
||||
@ -149,13 +156,12 @@ public class Range extends NamedExpression implements ScriptWeaver {
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
throw new SqlIllegalArgumentException("Not supported yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attribute toAttribute() {
|
||||
return new FieldAttribute(location(), "not yet implemented",
|
||||
new EsField("not yet implemented", DataType.UNSUPPORTED, emptyMap(), false));
|
||||
BinaryComparisonPipe lowerPipe = new BinaryComparisonPipe(location(), this, Expressions.pipe(value()), Expressions.pipe(lower()),
|
||||
includeLower() ? BinaryComparisonOperation.GTE : BinaryComparisonOperation.GT);
|
||||
BinaryComparisonPipe upperPipe = new BinaryComparisonPipe(location(), this, Expressions.pipe(value()), Expressions.pipe(upper()),
|
||||
includeUpper() ? BinaryComparisonOperation.LTE : BinaryComparisonOperation.LT);
|
||||
BinaryLogicPipe and = new BinaryLogicPipe(location(), this, lowerPipe, upperPipe, BinaryLogicOperation.AND);
|
||||
return and;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -181,13 +187,28 @@ public class Range extends NamedExpression implements ScriptWeaver {
|
||||
&& Objects.equals(upper, other.upper);
|
||||
}
|
||||
|
||||
private static String defaultName(Expression value, Expression lower, Expression upper, boolean includeLower, boolean includeUpper) {
|
||||
private static String name(Expression value, Expression lower, Expression upper, boolean includeLower, boolean includeUpper) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(lower);
|
||||
sb.append(Expressions.name(lower));
|
||||
if (!(lower instanceof Literal)) {
|
||||
sb.insert(0, "(");
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append(includeLower ? " <= " : " < ");
|
||||
sb.append(value);
|
||||
int pos = sb.length();
|
||||
sb.append(Expressions.name(value));
|
||||
if (!(value instanceof Literal)) {
|
||||
sb.insert(pos, "(");
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append(includeUpper ? " <= " : " < ");
|
||||
sb.append(upper);
|
||||
pos = sb.length();
|
||||
sb.append(Expressions.name(upper));
|
||||
if (!(upper instanceof Literal)) {
|
||||
sb.insert(pos, "(");
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
@ -3,19 +3,18 @@
|
||||
* 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.expression.predicate;
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.logical;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator.Negateable;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class And extends BinaryLogic implements Negateable {
|
||||
|
||||
public And(Location location, Expression left, Expression right) {
|
||||
super(location, left, right, "&&");
|
||||
super(location, left, right, BinaryLogicOperation.AND);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -24,22 +23,17 @@ public class And extends BinaryLogic implements Negateable {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BinaryOperator replaceChildren(Expression newLeft, Expression newRight) {
|
||||
protected And replaceChildren(Expression newLeft, Expression newRight) {
|
||||
return new And(location(), newLeft, newRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return Objects.equals(left().fold(), Boolean.TRUE) && Objects.equals(right().fold(), Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Or negate() {
|
||||
return new Or(location(), new Not(location(), left()), new Not(location(), right()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public And swapLeftAndRight() {
|
||||
return new And(location(), right(), left());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Or negate() {
|
||||
return new Or(location(), new Not(location(), left()), new Not(location(), right()));
|
||||
}
|
||||
}
|
@ -3,19 +3,20 @@
|
||||
* 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.expression.predicate;
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.logical;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.AggNameInput;
|
||||
import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
public abstract class BinaryLogic extends BinaryOperator {
|
||||
public abstract class BinaryLogic extends BinaryOperator<Boolean, Boolean, Boolean, BinaryLogicOperation> {
|
||||
|
||||
protected BinaryLogic(Location location, Expression left, Expression right, String symbol) {
|
||||
super(location, left, right, symbol);
|
||||
protected BinaryLogic(Location location, Expression left, Expression right, BinaryLogicOperation operation) {
|
||||
super(location, left, right, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -29,13 +30,8 @@ public abstract class BinaryLogic extends BinaryOperator {
|
||||
"'%s' requires type %s not %s", symbol(), DataType.BOOLEAN.sqlName(), inputType.sqlName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
return new ScriptTemplate("<not yet supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
return new AggNameInput(location(), this, "<not yet supported>");
|
||||
return new BinaryLogicPipe(location(), this, Expressions.pipe(left()), Expressions.pipe(right()), function());
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.expression.predicate.logical;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.BinaryPipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class BinaryLogicPipe extends BinaryPipe {
|
||||
|
||||
private final BinaryLogicOperation operation;
|
||||
|
||||
public BinaryLogicPipe(Location location, Expression expression, Pipe left, Pipe right, BinaryLogicOperation operation) {
|
||||
super(location, expression, left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<BinaryLogicPipe> info() {
|
||||
return NodeInfo.create(this, BinaryLogicPipe::new, expression(), left(), right(), operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BinaryPipe replaceChildren(Pipe left, Pipe right) {
|
||||
return new BinaryLogicPipe(location(), expression(), left, right, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryLogicProcessor asProcessor() {
|
||||
return new BinaryLogicProcessor(left().asProcessor(), right().asProcessor(), operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (super.equals(obj)) {
|
||||
BinaryLogicPipe other = (BinaryLogicPipe) obj;
|
||||
return Objects.equals(operation, other.operation);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.expression.predicate.logical;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.FunctionalBinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.PredicateBiFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class BinaryLogicProcessor extends FunctionalBinaryProcessor<Boolean, Boolean, Boolean, BinaryLogicOperation> {
|
||||
|
||||
public enum BinaryLogicOperation implements PredicateBiFunction<Boolean, Boolean, Boolean> {
|
||||
|
||||
AND((l, r) -> {
|
||||
if (Boolean.FALSE.equals(l) || Boolean.FALSE.equals(r)) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if (l == null || r == null) {
|
||||
return null;
|
||||
}
|
||||
return l.booleanValue() && r.booleanValue();
|
||||
}, "&&"),
|
||||
OR((l, r) -> {
|
||||
if (Boolean.TRUE.equals(l) || Boolean.TRUE.equals(r)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
if (l == null || r == null) {
|
||||
return null;
|
||||
}
|
||||
return l.booleanValue() || r.booleanValue();
|
||||
}, "||");
|
||||
|
||||
private final BiFunction<Boolean, Boolean, Boolean> process;
|
||||
private final String symbol;
|
||||
|
||||
BinaryLogicOperation(BiFunction<Boolean, Boolean, Boolean> process, String symbol) {
|
||||
this.process = process;
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String symbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean apply(Boolean left, Boolean right) {
|
||||
return process.apply(left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Boolean doApply(Boolean left, Boolean right) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String NAME = "lb";
|
||||
|
||||
public BinaryLogicProcessor(Processor left, Processor right, BinaryLogicOperation operation) {
|
||||
super(left, right, operation);
|
||||
}
|
||||
|
||||
public BinaryLogicProcessor(StreamInput in) throws IOException {
|
||||
super(in, i -> i.readEnum(BinaryLogicOperation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkParameter(Object param) {
|
||||
if (!(param instanceof Boolean)) {
|
||||
throw new SqlIllegalArgumentException("A boolean is required; received {}", param);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
* 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.expression.predicate;
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.logical;
|
||||
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
@ -3,19 +3,18 @@
|
||||
* 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.expression.predicate;
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.logical;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator.Negateable;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Or extends BinaryLogic implements Negateable {
|
||||
|
||||
public Or(Location location, Expression left, Expression right) {
|
||||
super(location, left, right, "||");
|
||||
super(location, left, right, BinaryLogicOperation.OR);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -24,15 +23,10 @@ public class Or extends BinaryLogic implements Negateable {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BinaryOperator replaceChildren(Expression newLeft, Expression newRight) {
|
||||
protected Or replaceChildren(Expression newLeft, Expression newRight) {
|
||||
return new Or(location(), newLeft, newRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return Objects.equals(left().fold(), Boolean.TRUE) || Objects.equals(right().fold(), Boolean.TRUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Or swapLeftAndRight() {
|
||||
return new Or(location(), right(), left());
|
@ -8,25 +8,16 @@ package org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.elasticsearch.xpack.sql.type.DataTypeConversion;
|
||||
|
||||
import java.util.Locale;
|
||||
public abstract class ArithmeticOperation extends BinaryOperator<Number, Number, Number, BinaryArithmeticOperation> {
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
public abstract class ArithmeticOperation extends BinaryOperator {
|
||||
|
||||
private final BinaryArithmeticOperation operation;
|
||||
|
||||
ArithmeticOperation(Location location, Expression left, Expression right, BinaryArithmeticOperation operation) {
|
||||
super(location, left, right, operation.symbol());
|
||||
this.operation = operation;
|
||||
protected ArithmeticOperation(Location location, Expression left, Expression right, BinaryArithmeticOperation operation) {
|
||||
super(location, left, right, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -46,26 +37,8 @@ public abstract class ArithmeticOperation extends BinaryOperator {
|
||||
return DataTypeConversion.commonType(left().dataType(), right().dataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return operation.apply((Number) left().fold(), (Number) right().fold());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
String op = operation.symbol();
|
||||
// escape %
|
||||
if (operation == BinaryArithmeticOperation.MOD) {
|
||||
op = "%" + op;
|
||||
}
|
||||
return new ScriptTemplate(format(Locale.ROOT, "(%s) %s (%s)", leftScript.template(), op, rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params()).script(rightScript.params())
|
||||
.build(), dataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
return new BinaryArithmeticPipe(location(), this, Expressions.pipe(left()), Expressions.pipe(right()), operation);
|
||||
return new BinaryArithmeticPipe(location(), this, Expressions.pipe(left()), Expressions.pipe(right()), function());
|
||||
}
|
||||
}
|
@ -18,16 +18,14 @@ public class BinaryArithmeticPipe extends BinaryPipe {
|
||||
|
||||
private final BinaryArithmeticOperation operation;
|
||||
|
||||
public BinaryArithmeticPipe(Location location, Expression expression, Pipe left,
|
||||
Pipe right, BinaryArithmeticOperation operation) {
|
||||
public BinaryArithmeticPipe(Location location, Expression expression, Pipe left, Pipe right, BinaryArithmeticOperation operation) {
|
||||
super(location, expression, left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<BinaryArithmeticPipe> info() {
|
||||
return NodeInfo.create(this, BinaryArithmeticPipe::new,
|
||||
expression(), left(), right(), operation);
|
||||
return NodeInfo.create(this, BinaryArithmeticPipe::new, expression(), left(), right(), operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,18 +6,18 @@
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryNumericProcessor;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.FunctionalBinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.PredicateBiFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class BinaryArithmeticProcessor extends BinaryNumericProcessor<BinaryArithmeticOperation> {
|
||||
public class BinaryArithmeticProcessor extends FunctionalBinaryProcessor<Number, Number, Number, BinaryArithmeticOperation> {
|
||||
|
||||
public enum BinaryArithmeticOperation implements BiFunction<Number, Number, Number> {
|
||||
|
||||
public enum BinaryArithmeticOperation implements PredicateBiFunction<Number, Number, Number> {
|
||||
ADD(Arithmetics::add, "+"),
|
||||
SUB(Arithmetics::sub, "-"),
|
||||
MUL(Arithmetics::mul, "*"),
|
||||
@ -32,12 +32,13 @@ public class BinaryArithmeticProcessor extends BinaryNumericProcessor<BinaryArit
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String symbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Number apply(Number left, Number right) {
|
||||
public final Number doApply(Number left, Number right) {
|
||||
return process.apply(left, right);
|
||||
}
|
||||
|
||||
@ -57,13 +58,15 @@ public class BinaryArithmeticProcessor extends BinaryNumericProcessor<BinaryArit
|
||||
super(in, i -> i.readEnum(BinaryArithmeticOperation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {
|
||||
out.writeEnum(operation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkParameter(Object param) {
|
||||
if (!(param instanceof Number)) {
|
||||
throw new SqlIllegalArgumentException("A number is required; received {}", param);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,25 +8,16 @@ package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
// marker class to indicate operations that rely on values
|
||||
public abstract class BinaryComparison extends BinaryOperator {
|
||||
public abstract class BinaryComparison extends BinaryOperator<Object, Object, Boolean, BinaryComparisonOperation> {
|
||||
|
||||
private final BinaryComparisonOperation operation;
|
||||
|
||||
public BinaryComparison(Location location, Expression left, Expression right, BinaryComparisonOperation operation) {
|
||||
super(location, left, right, operation.symbol());
|
||||
this.operation = operation;
|
||||
protected BinaryComparison(Location location, Expression left, Expression right, BinaryComparisonOperation operation) {
|
||||
super(location, left, right, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -34,25 +25,6 @@ public abstract class BinaryComparison extends BinaryOperator {
|
||||
return TypeResolution.TYPE_RESOLVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
String op = operation.symbol();
|
||||
return new ScriptTemplate(format(Locale.ROOT, "(%s) %s (%s)", leftScript.template(), op, rightScript.template()),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params()).script(rightScript.params())
|
||||
.build(), dataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
return new BinaryComparisonPipe(location(), this, Expressions.pipe(left()), Expressions.pipe(right()), operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return operation.apply(left().fold(), right().fold());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Expression canonicalize() {
|
||||
return left().hashCode() > right().hashCode() ? swapLeftAndRight() : this;
|
||||
@ -63,8 +35,9 @@ public abstract class BinaryComparison extends BinaryOperator {
|
||||
return DataType.BOOLEAN;
|
||||
}
|
||||
|
||||
public static Integer compare(Object left, Object right) {
|
||||
return Comparisons.compare(left, right);
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
return new BinaryComparisonPipe(location(), this, Expressions.pipe(left()), Expressions.pipe(right()), function());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -77,4 +50,8 @@ public abstract class BinaryComparison extends BinaryOperator {
|
||||
sb.append(right());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static Integer compare(Object left, Object right) {
|
||||
return Comparisons.compare(left, right);
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ public class BinaryComparisonPipe extends BinaryPipe {
|
||||
|
||||
private final BinaryComparisonOperation operation;
|
||||
|
||||
public BinaryComparisonPipe(Location location, Expression expression, Pipe left,
|
||||
Pipe right, BinaryComparisonOperation operation) {
|
||||
public BinaryComparisonPipe(Location location, Expression expression, Pipe left, Pipe right, BinaryComparisonOperation operation) {
|
||||
super(location, expression, left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
@ -6,16 +6,17 @@
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.FunctionalBinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.PredicateBiFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class BinaryComparisonProcessor extends BinaryOperatorProcessor<BinaryComparisonOperation> {
|
||||
public class BinaryComparisonProcessor extends FunctionalBinaryProcessor<Object, Object, Boolean, BinaryComparisonOperation> {
|
||||
|
||||
public enum BinaryComparisonOperation implements BiFunction<Object, Object, Boolean> {
|
||||
public enum BinaryComparisonOperation implements PredicateBiFunction<Object, Object, Boolean> {
|
||||
|
||||
EQ(Comparisons::eq, "=="),
|
||||
GT(Comparisons::gt, ">"),
|
||||
@ -31,12 +32,13 @@ public class BinaryComparisonProcessor extends BinaryOperatorProcessor<BinaryCom
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String symbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Boolean apply(Object left, Object right) {
|
||||
public final Boolean doApply(Object left, Object right) {
|
||||
return process.apply(left, right);
|
||||
}
|
||||
|
||||
@ -56,11 +58,6 @@ public class BinaryComparisonProcessor extends BinaryOperatorProcessor<BinaryCom
|
||||
super(in, i -> i.readEnum(BinaryComparisonOperation.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {
|
||||
out.writeEnum(operation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return NAME;
|
||||
|
@ -1,76 +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.expression.predicate.operator.comparison;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.BinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public abstract class BinaryOperatorProcessor<O extends Enum<?> & BiFunction<Object, Object, Boolean>> extends BinaryProcessor {
|
||||
|
||||
private final O operation;
|
||||
|
||||
protected BinaryOperatorProcessor(Processor left, Processor right, O operation) {
|
||||
super(left, right);
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
protected BinaryOperatorProcessor(StreamInput in, Reader<O> reader) throws IOException {
|
||||
super(in);
|
||||
operation = reader.read(in);
|
||||
}
|
||||
|
||||
protected O operation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doProcess(Object left, Object right) {
|
||||
if (left == null || right == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
checkParameter(left);
|
||||
checkParameter(right);
|
||||
|
||||
return operation.apply(left, right);
|
||||
}
|
||||
|
||||
protected void checkParameter(Object param) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BinaryOperatorProcessor<?> other = (BinaryOperatorProcessor<?>) obj;
|
||||
return Objects.equals(operation, other.operation)
|
||||
&& Objects.equals(left(), other.left())
|
||||
&& Objects.equals(right(), other.right());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.ROOT, "(%s %s %s)", left(), operation, right());
|
||||
}
|
||||
}
|
@ -5,62 +5,32 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.regex;
|
||||
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryPredicate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Like extends BinaryPredicate {
|
||||
public class Like extends RegexMatch {
|
||||
|
||||
public Like(Location location, Expression left, LikePattern right) {
|
||||
super(location, left, right, "LIKE");
|
||||
super(location, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<Like> info() {
|
||||
return NodeInfo.create(this, Like::new, left(), right());
|
||||
return NodeInfo.create(this, Like::new, left(), pattern());
|
||||
}
|
||||
|
||||
public LikePattern pattern() {
|
||||
return (LikePattern) right();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BinaryPredicate replaceChildren(Expression newLeft, Expression newRight) {
|
||||
protected Like replaceChildren(Expression newLeft, Expression newRight) {
|
||||
return new Like(location(), newLeft, (LikePattern) newRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LikePattern right() {
|
||||
return (LikePattern) super.right();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean foldable() {
|
||||
// right() is not directly foldable in any context but Like can fold it.
|
||||
return left().foldable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
Pattern p = Pattern.compile(right().asJavaRegex());
|
||||
return p.matcher(left().fold().toString()).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return DataType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
throw new SqlIllegalArgumentException("Not supported yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
throw new SqlIllegalArgumentException("Not supported yet");
|
||||
protected String asString(Expression pattern) {
|
||||
return ((LikePattern) pattern).asJavaRegex();
|
||||
}
|
||||
}
|
||||
|
@ -5,57 +5,29 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.regex;
|
||||
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.Literal;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryPredicate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RLike extends BinaryPredicate {
|
||||
public class RLike extends RegexMatch {
|
||||
|
||||
public RLike(Location location, Expression left, Literal right) {
|
||||
super(location, left, right, "RLIKE");
|
||||
super(location, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<RLike> info() {
|
||||
return NodeInfo.create(this, RLike::new, left(), right());
|
||||
return NodeInfo.create(this, RLike::new, left(), (Literal) right());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BinaryPredicate replaceChildren(Expression newLeft, Expression newRight) {
|
||||
protected RLike replaceChildren(Expression newLeft, Expression newRight) {
|
||||
return new RLike(location(), newLeft, (Literal) newRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Literal right() {
|
||||
return (Literal) super.right();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
Pattern p = Pattern.compile(right().fold().toString());
|
||||
return p.matcher(left().fold().toString()).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return DataType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||
throw new SqlIllegalArgumentException("Not supported yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
throw new SqlIllegalArgumentException("Not supported yet");
|
||||
protected String asString(Expression pattern) {
|
||||
return pattern.fold().toString();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.expression.predicate.regex;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.regex.RegexProcessor.RegexOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
public abstract class RegexMatch extends BinaryPredicate<String, String, Boolean, RegexOperation> {
|
||||
|
||||
protected RegexMatch(Location location, Expression value, Expression pattern) {
|
||||
super(location, value, pattern, RegexOperation.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return DataType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean foldable() {
|
||||
// right() is not directly foldable in any context but Like can fold it.
|
||||
return left().foldable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean fold() {
|
||||
Object val = left().fold();
|
||||
val = val != null ? val.toString() : val;
|
||||
return function().apply((String) val, asString(right()));
|
||||
}
|
||||
|
||||
protected abstract String asString(Expression pattern);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.expression.predicate.regex;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.BinaryPipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
|
||||
public class RegexPipe extends BinaryPipe {
|
||||
|
||||
public RegexPipe(Location location, Expression expression, Pipe left, Pipe right) {
|
||||
super(location, expression, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<RegexPipe> info() {
|
||||
return NodeInfo.create(this, RegexPipe::new, expression(), left(), right());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BinaryPipe replaceChildren(Pipe left, Pipe right) {
|
||||
return new RegexPipe(location(), expression(), left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegexProcessor asProcessor() {
|
||||
return new RegexProcessor(left().asProcessor(), right().asProcessor());
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.expression.predicate.regex;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.BinaryProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.PredicateBiFunction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RegexProcessor extends BinaryProcessor {
|
||||
|
||||
public static class RegexOperation implements PredicateBiFunction<String, String, Boolean> {
|
||||
|
||||
public static final RegexOperation INSTANCE = new RegexOperation();
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return symbol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String symbol() {
|
||||
return "REGEX";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean doApply(String value, String pattern) {
|
||||
return match(value, pattern);
|
||||
}
|
||||
|
||||
public static Boolean match(Object value, Object pattern) {
|
||||
if (value == null || pattern == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Pattern p = Pattern.compile(pattern.toString());
|
||||
return p.matcher(value.toString()).matches();
|
||||
}
|
||||
}
|
||||
|
||||
public static final String NAME = "rgx";
|
||||
|
||||
public RegexProcessor(Processor value, Processor pattern) {
|
||||
super(value, pattern);
|
||||
}
|
||||
|
||||
public RegexProcessor(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doProcess(Object value, Object pattern) {
|
||||
return RegexOperation.match(value, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkParameter(Object param) {
|
||||
if (!(param instanceof String || param instanceof Character)) {
|
||||
throw new SqlIllegalArgumentException("A string/char is required; received [{}]", param);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWrite(StreamOutput out) throws IOException {}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(left(), right());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RegexProcessor other = (RegexProcessor) obj;
|
||||
return Objects.equals(left(), other.left()) && Objects.equals(right(), other.right());
|
||||
}
|
||||
}
|
@ -36,14 +36,14 @@ import org.elasticsearch.xpack.sql.expression.function.aggregate.Stats;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunctionAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator.Negateable;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Or;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Predicates;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Range;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Or;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparison;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThan;
|
||||
@ -1138,7 +1138,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
||||
@Override
|
||||
protected Expression rule(Expression e) {
|
||||
if (e instanceof BinaryPredicate) {
|
||||
return simplifyAndOr((BinaryPredicate) e);
|
||||
return simplifyAndOr((BinaryPredicate<?, ?, ?, ?>) e);
|
||||
}
|
||||
if (e instanceof Not) {
|
||||
return simplifyNot((Not) e);
|
||||
@ -1147,7 +1147,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
||||
return e;
|
||||
}
|
||||
|
||||
private Expression simplifyAndOr(BinaryPredicate bc) {
|
||||
private Expression simplifyAndOr(BinaryPredicate<?, ?, ?, ?> bc) {
|
||||
Expression l = bc.left();
|
||||
Expression r = bc.right();
|
||||
|
||||
@ -1293,10 +1293,10 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
||||
|
||||
@Override
|
||||
protected Expression rule(Expression e) {
|
||||
return e instanceof BinaryOperator ? literalToTheRight((BinaryOperator) e) : e;
|
||||
return e instanceof BinaryOperator ? literalToTheRight((BinaryOperator<?, ?, ?, ?>) e) : e;
|
||||
}
|
||||
|
||||
private Expression literalToTheRight(BinaryOperator be) {
|
||||
private Expression literalToTheRight(BinaryOperator<?, ?, ?, ?> be) {
|
||||
return be.left() instanceof Literal && !(be.right() instanceof Literal) ? be.swapLeftAndRight() : be;
|
||||
}
|
||||
}
|
||||
|
@ -17,21 +17,22 @@ import org.elasticsearch.xpack.sql.expression.Exists;
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.Literal;
|
||||
import org.elasticsearch.xpack.sql.expression.Order;
|
||||
import org.elasticsearch.xpack.sql.expression.Order.NullsPosition;
|
||||
import org.elasticsearch.xpack.sql.expression.ScalarSubquery;
|
||||
import org.elasticsearch.xpack.sql.expression.UnresolvedAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.UnresolvedStar;
|
||||
import org.elasticsearch.xpack.sql.expression.function.Function;
|
||||
import org.elasticsearch.xpack.sql.expression.function.UnresolvedFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.In;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.IsNotNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Or;
|
||||
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.MultiMatchQueryPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.StringQueryPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Or;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Add;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Div;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Mod;
|
||||
@ -349,7 +350,8 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
||||
@Override
|
||||
public Order visitOrderBy(OrderByContext ctx) {
|
||||
return new Order(source(ctx), expression(ctx.expression()),
|
||||
ctx.DESC() != null ? Order.OrderDirection.DESC : Order.OrderDirection.ASC);
|
||||
ctx.DESC() != null ? Order.OrderDirection.DESC : Order.OrderDirection.ASC,
|
||||
ctx.NULLS() != null ? (ctx.FIRST() != null ? NullsPosition.FIRST : NullsPosition.LAST) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,19 +20,19 @@ class SqlBaseLexer extends Lexer {
|
||||
T__0=1, T__1=2, T__2=3, T__3=4, ALL=5, ANALYZE=6, ANALYZED=7, AND=8, ANY=9,
|
||||
AS=10, ASC=11, BETWEEN=12, BY=13, CAST=14, CATALOG=15, CATALOGS=16, COLUMNS=17,
|
||||
DEBUG=18, DESC=19, DESCRIBE=20, DISTINCT=21, ESCAPE=22, EXECUTABLE=23,
|
||||
EXISTS=24, EXPLAIN=25, EXTRACT=26, FALSE=27, FORMAT=28, FROM=29, FULL=30,
|
||||
FUNCTIONS=31, GRAPHVIZ=32, GROUP=33, HAVING=34, IN=35, INNER=36, IS=37,
|
||||
JOIN=38, LEFT=39, LIKE=40, LIMIT=41, MAPPED=42, MATCH=43, NATURAL=44,
|
||||
NOT=45, NULL=46, ON=47, OPTIMIZED=48, OR=49, ORDER=50, OUTER=51, PARSED=52,
|
||||
PHYSICAL=53, PLAN=54, RIGHT=55, RLIKE=56, QUERY=57, SCHEMAS=58, SELECT=59,
|
||||
SHOW=60, SYS=61, TABLE=62, TABLES=63, TEXT=64, TRUE=65, TYPE=66, TYPES=67,
|
||||
USING=68, VERIFY=69, WHERE=70, WITH=71, ESCAPE_ESC=72, FUNCTION_ESC=73,
|
||||
LIMIT_ESC=74, DATE_ESC=75, TIME_ESC=76, TIMESTAMP_ESC=77, GUID_ESC=78,
|
||||
ESC_END=79, EQ=80, NEQ=81, LT=82, LTE=83, GT=84, GTE=85, PLUS=86, MINUS=87,
|
||||
ASTERISK=88, SLASH=89, PERCENT=90, CONCAT=91, DOT=92, PARAM=93, STRING=94,
|
||||
INTEGER_VALUE=95, DECIMAL_VALUE=96, IDENTIFIER=97, DIGIT_IDENTIFIER=98,
|
||||
TABLE_IDENTIFIER=99, QUOTED_IDENTIFIER=100, BACKQUOTED_IDENTIFIER=101,
|
||||
SIMPLE_COMMENT=102, BRACKETED_COMMENT=103, WS=104, UNRECOGNIZED=105;
|
||||
EXISTS=24, EXPLAIN=25, EXTRACT=26, FALSE=27, FIRST=28, FORMAT=29, FROM=30,
|
||||
FULL=31, FUNCTIONS=32, GRAPHVIZ=33, GROUP=34, HAVING=35, IN=36, INNER=37,
|
||||
IS=38, JOIN=39, LAST=40, LEFT=41, LIKE=42, LIMIT=43, MAPPED=44, MATCH=45,
|
||||
NATURAL=46, NOT=47, NULL=48, NULLS=49, ON=50, OPTIMIZED=51, OR=52, ORDER=53,
|
||||
OUTER=54, PARSED=55, PHYSICAL=56, PLAN=57, RIGHT=58, RLIKE=59, QUERY=60,
|
||||
SCHEMAS=61, SELECT=62, SHOW=63, SYS=64, TABLE=65, TABLES=66, TEXT=67,
|
||||
TRUE=68, TYPE=69, TYPES=70, USING=71, VERIFY=72, WHERE=73, WITH=74, ESCAPE_ESC=75,
|
||||
FUNCTION_ESC=76, LIMIT_ESC=77, DATE_ESC=78, TIME_ESC=79, TIMESTAMP_ESC=80,
|
||||
GUID_ESC=81, ESC_END=82, EQ=83, NEQ=84, LT=85, LTE=86, GT=87, GTE=88,
|
||||
PLUS=89, MINUS=90, ASTERISK=91, SLASH=92, PERCENT=93, CONCAT=94, DOT=95,
|
||||
PARAM=96, STRING=97, INTEGER_VALUE=98, DECIMAL_VALUE=99, IDENTIFIER=100,
|
||||
DIGIT_IDENTIFIER=101, TABLE_IDENTIFIER=102, QUOTED_IDENTIFIER=103, BACKQUOTED_IDENTIFIER=104,
|
||||
SIMPLE_COMMENT=105, BRACKETED_COMMENT=106, WS=107, UNRECOGNIZED=108;
|
||||
public static String[] modeNames = {
|
||||
"DEFAULT_MODE"
|
||||
};
|
||||
@ -41,18 +41,18 @@ class SqlBaseLexer extends Lexer {
|
||||
"T__0", "T__1", "T__2", "T__3", "ALL", "ANALYZE", "ANALYZED", "AND", "ANY",
|
||||
"AS", "ASC", "BETWEEN", "BY", "CAST", "CATALOG", "CATALOGS", "COLUMNS",
|
||||
"DEBUG", "DESC", "DESCRIBE", "DISTINCT", "ESCAPE", "EXECUTABLE", "EXISTS",
|
||||
"EXPLAIN", "EXTRACT", "FALSE", "FORMAT", "FROM", "FULL", "FUNCTIONS",
|
||||
"GRAPHVIZ", "GROUP", "HAVING", "IN", "INNER", "IS", "JOIN", "LEFT", "LIKE",
|
||||
"LIMIT", "MAPPED", "MATCH", "NATURAL", "NOT", "NULL", "ON", "OPTIMIZED",
|
||||
"OR", "ORDER", "OUTER", "PARSED", "PHYSICAL", "PLAN", "RIGHT", "RLIKE",
|
||||
"QUERY", "SCHEMAS", "SELECT", "SHOW", "SYS", "TABLE", "TABLES", "TEXT",
|
||||
"TRUE", "TYPE", "TYPES", "USING", "VERIFY", "WHERE", "WITH", "ESCAPE_ESC",
|
||||
"FUNCTION_ESC", "LIMIT_ESC", "DATE_ESC", "TIME_ESC", "TIMESTAMP_ESC",
|
||||
"GUID_ESC", "ESC_END", "EQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS",
|
||||
"MINUS", "ASTERISK", "SLASH", "PERCENT", "CONCAT", "DOT", "PARAM", "STRING",
|
||||
"INTEGER_VALUE", "DECIMAL_VALUE", "IDENTIFIER", "DIGIT_IDENTIFIER", "TABLE_IDENTIFIER",
|
||||
"QUOTED_IDENTIFIER", "BACKQUOTED_IDENTIFIER", "EXPONENT", "DIGIT", "LETTER",
|
||||
"SIMPLE_COMMENT", "BRACKETED_COMMENT", "WS", "UNRECOGNIZED"
|
||||
"EXPLAIN", "EXTRACT", "FALSE", "FIRST", "FORMAT", "FROM", "FULL", "FUNCTIONS",
|
||||
"GRAPHVIZ", "GROUP", "HAVING", "IN", "INNER", "IS", "JOIN", "LAST", "LEFT",
|
||||
"LIKE", "LIMIT", "MAPPED", "MATCH", "NATURAL", "NOT", "NULL", "NULLS",
|
||||
"ON", "OPTIMIZED", "OR", "ORDER", "OUTER", "PARSED", "PHYSICAL", "PLAN",
|
||||
"RIGHT", "RLIKE", "QUERY", "SCHEMAS", "SELECT", "SHOW", "SYS", "TABLE",
|
||||
"TABLES", "TEXT", "TRUE", "TYPE", "TYPES", "USING", "VERIFY", "WHERE",
|
||||
"WITH", "ESCAPE_ESC", "FUNCTION_ESC", "LIMIT_ESC", "DATE_ESC", "TIME_ESC",
|
||||
"TIMESTAMP_ESC", "GUID_ESC", "ESC_END", "EQ", "NEQ", "LT", "LTE", "GT",
|
||||
"GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "CONCAT", "DOT",
|
||||
"PARAM", "STRING", "INTEGER_VALUE", "DECIMAL_VALUE", "IDENTIFIER", "DIGIT_IDENTIFIER",
|
||||
"TABLE_IDENTIFIER", "QUOTED_IDENTIFIER", "BACKQUOTED_IDENTIFIER", "EXPONENT",
|
||||
"DIGIT", "LETTER", "SIMPLE_COMMENT", "BRACKETED_COMMENT", "WS", "UNRECOGNIZED"
|
||||
};
|
||||
|
||||
private static final String[] _LITERAL_NAMES = {
|
||||
@ -60,32 +60,33 @@ class SqlBaseLexer extends Lexer {
|
||||
"'AND'", "'ANY'", "'AS'", "'ASC'", "'BETWEEN'", "'BY'", "'CAST'", "'CATALOG'",
|
||||
"'CATALOGS'", "'COLUMNS'", "'DEBUG'", "'DESC'", "'DESCRIBE'", "'DISTINCT'",
|
||||
"'ESCAPE'", "'EXECUTABLE'", "'EXISTS'", "'EXPLAIN'", "'EXTRACT'", "'FALSE'",
|
||||
"'FORMAT'", "'FROM'", "'FULL'", "'FUNCTIONS'", "'GRAPHVIZ'", "'GROUP'",
|
||||
"'HAVING'", "'IN'", "'INNER'", "'IS'", "'JOIN'", "'LEFT'", "'LIKE'", "'LIMIT'",
|
||||
"'MAPPED'", "'MATCH'", "'NATURAL'", "'NOT'", "'NULL'", "'ON'", "'OPTIMIZED'",
|
||||
"'OR'", "'ORDER'", "'OUTER'", "'PARSED'", "'PHYSICAL'", "'PLAN'", "'RIGHT'",
|
||||
"'RLIKE'", "'QUERY'", "'SCHEMAS'", "'SELECT'", "'SHOW'", "'SYS'", "'TABLE'",
|
||||
"'TABLES'", "'TEXT'", "'TRUE'", "'TYPE'", "'TYPES'", "'USING'", "'VERIFY'",
|
||||
"'WHERE'", "'WITH'", "'{ESCAPE'", "'{FN'", "'{LIMIT'", "'{D'", "'{T'",
|
||||
"'{TS'", "'{GUID'", "'}'", "'='", null, "'<'", "'<='", "'>'", "'>='",
|
||||
"'+'", "'-'", "'*'", "'/'", "'%'", "'||'", "'.'", "'?'"
|
||||
"'FIRST'", "'FORMAT'", "'FROM'", "'FULL'", "'FUNCTIONS'", "'GRAPHVIZ'",
|
||||
"'GROUP'", "'HAVING'", "'IN'", "'INNER'", "'IS'", "'JOIN'", "'LAST'",
|
||||
"'LEFT'", "'LIKE'", "'LIMIT'", "'MAPPED'", "'MATCH'", "'NATURAL'", "'NOT'",
|
||||
"'NULL'", "'NULLS'", "'ON'", "'OPTIMIZED'", "'OR'", "'ORDER'", "'OUTER'",
|
||||
"'PARSED'", "'PHYSICAL'", "'PLAN'", "'RIGHT'", "'RLIKE'", "'QUERY'", "'SCHEMAS'",
|
||||
"'SELECT'", "'SHOW'", "'SYS'", "'TABLE'", "'TABLES'", "'TEXT'", "'TRUE'",
|
||||
"'TYPE'", "'TYPES'", "'USING'", "'VERIFY'", "'WHERE'", "'WITH'", "'{ESCAPE'",
|
||||
"'{FN'", "'{LIMIT'", "'{D'", "'{T'", "'{TS'", "'{GUID'", "'}'", "'='",
|
||||
null, "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'",
|
||||
"'||'", "'.'", "'?'"
|
||||
};
|
||||
private static final String[] _SYMBOLIC_NAMES = {
|
||||
null, null, null, null, null, "ALL", "ANALYZE", "ANALYZED", "AND", "ANY",
|
||||
"AS", "ASC", "BETWEEN", "BY", "CAST", "CATALOG", "CATALOGS", "COLUMNS",
|
||||
"DEBUG", "DESC", "DESCRIBE", "DISTINCT", "ESCAPE", "EXECUTABLE", "EXISTS",
|
||||
"EXPLAIN", "EXTRACT", "FALSE", "FORMAT", "FROM", "FULL", "FUNCTIONS",
|
||||
"GRAPHVIZ", "GROUP", "HAVING", "IN", "INNER", "IS", "JOIN", "LEFT", "LIKE",
|
||||
"LIMIT", "MAPPED", "MATCH", "NATURAL", "NOT", "NULL", "ON", "OPTIMIZED",
|
||||
"OR", "ORDER", "OUTER", "PARSED", "PHYSICAL", "PLAN", "RIGHT", "RLIKE",
|
||||
"QUERY", "SCHEMAS", "SELECT", "SHOW", "SYS", "TABLE", "TABLES", "TEXT",
|
||||
"TRUE", "TYPE", "TYPES", "USING", "VERIFY", "WHERE", "WITH", "ESCAPE_ESC",
|
||||
"FUNCTION_ESC", "LIMIT_ESC", "DATE_ESC", "TIME_ESC", "TIMESTAMP_ESC",
|
||||
"GUID_ESC", "ESC_END", "EQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS",
|
||||
"MINUS", "ASTERISK", "SLASH", "PERCENT", "CONCAT", "DOT", "PARAM", "STRING",
|
||||
"INTEGER_VALUE", "DECIMAL_VALUE", "IDENTIFIER", "DIGIT_IDENTIFIER", "TABLE_IDENTIFIER",
|
||||
"QUOTED_IDENTIFIER", "BACKQUOTED_IDENTIFIER", "SIMPLE_COMMENT", "BRACKETED_COMMENT",
|
||||
"WS", "UNRECOGNIZED"
|
||||
"EXPLAIN", "EXTRACT", "FALSE", "FIRST", "FORMAT", "FROM", "FULL", "FUNCTIONS",
|
||||
"GRAPHVIZ", "GROUP", "HAVING", "IN", "INNER", "IS", "JOIN", "LAST", "LEFT",
|
||||
"LIKE", "LIMIT", "MAPPED", "MATCH", "NATURAL", "NOT", "NULL", "NULLS",
|
||||
"ON", "OPTIMIZED", "OR", "ORDER", "OUTER", "PARSED", "PHYSICAL", "PLAN",
|
||||
"RIGHT", "RLIKE", "QUERY", "SCHEMAS", "SELECT", "SHOW", "SYS", "TABLE",
|
||||
"TABLES", "TEXT", "TRUE", "TYPE", "TYPES", "USING", "VERIFY", "WHERE",
|
||||
"WITH", "ESCAPE_ESC", "FUNCTION_ESC", "LIMIT_ESC", "DATE_ESC", "TIME_ESC",
|
||||
"TIMESTAMP_ESC", "GUID_ESC", "ESC_END", "EQ", "NEQ", "LT", "LTE", "GT",
|
||||
"GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "CONCAT", "DOT",
|
||||
"PARAM", "STRING", "INTEGER_VALUE", "DECIMAL_VALUE", "IDENTIFIER", "DIGIT_IDENTIFIER",
|
||||
"TABLE_IDENTIFIER", "QUOTED_IDENTIFIER", "BACKQUOTED_IDENTIFIER", "SIMPLE_COMMENT",
|
||||
"BRACKETED_COMMENT", "WS", "UNRECOGNIZED"
|
||||
};
|
||||
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
|
||||
|
||||
@ -142,7 +143,7 @@ class SqlBaseLexer extends Lexer {
|
||||
public ATN getATN() { return _ATN; }
|
||||
|
||||
public static final String _serializedATN =
|
||||
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2k\u036f\b\1\4\2\t"+
|
||||
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2n\u0386\b\1\4\2\t"+
|
||||
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
|
||||
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
|
||||
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
|
||||
@ -154,54 +155,55 @@ class SqlBaseLexer extends Lexer {
|
||||
"\tI\4J\tJ\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S\tS\4T\tT"+
|
||||
"\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\4\\\t\\\4]\t]\4^\t^\4_\t_\4"+
|
||||
"`\t`\4a\ta\4b\tb\4c\tc\4d\td\4e\te\4f\tf\4g\tg\4h\th\4i\ti\4j\tj\4k\t"+
|
||||
"k\4l\tl\4m\tm\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\6\3\6\3\7\3\7"+
|
||||
"\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3"+
|
||||
"\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r"+
|
||||
"\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20"+
|
||||
"\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21"+
|
||||
"\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23"+
|
||||
"\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25"+
|
||||
"\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\27"+
|
||||
"\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\31"+
|
||||
"\3\31\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32"+
|
||||
"\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\34\3\34\3\34\3\34\3\34\3\34"+
|
||||
"\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\37\3\37"+
|
||||
"\3\37\3\37\3\37\3 \3 \3 \3 \3 \3 \3 \3 \3 \3 \3!\3!\3!\3!\3!\3!\3!\3!"+
|
||||
"\3!\3\"\3\"\3\"\3\"\3\"\3\"\3#\3#\3#\3#\3#\3#\3#\3$\3$\3$\3%\3%\3%\3%"+
|
||||
"\3%\3%\3&\3&\3&\3\'\3\'\3\'\3\'\3\'\3(\3(\3(\3(\3(\3)\3)\3)\3)\3)\3*\3"+
|
||||
"*\3*\3*\3*\3*\3+\3+\3+\3+\3+\3+\3+\3,\3,\3,\3,\3,\3,\3-\3-\3-\3-\3-\3"+
|
||||
"-\3-\3-\3.\3.\3.\3.\3/\3/\3/\3/\3/\3\60\3\60\3\60\3\61\3\61\3\61\3\61"+
|
||||
"\3\61\3\61\3\61\3\61\3\61\3\61\3\62\3\62\3\62\3\63\3\63\3\63\3\63\3\63"+
|
||||
"\3\63\3\64\3\64\3\64\3\64\3\64\3\64\3\65\3\65\3\65\3\65\3\65\3\65\3\65"+
|
||||
"\3\66\3\66\3\66\3\66\3\66\3\66\3\66\3\66\3\66\3\67\3\67\3\67\3\67\3\67"+
|
||||
"\38\38\38\38\38\38\39\39\39\39\39\39\3:\3:\3:\3:\3:\3:\3;\3;\3;\3;\3;"+
|
||||
"\3;\3;\3;\3<\3<\3<\3<\3<\3<\3<\3=\3=\3=\3=\3=\3>\3>\3>\3>\3?\3?\3?\3?"+
|
||||
"\3?\3?\3@\3@\3@\3@\3@\3@\3@\3A\3A\3A\3A\3A\3B\3B\3B\3B\3B\3C\3C\3C\3C"+
|
||||
"\3C\3D\3D\3D\3D\3D\3D\3E\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3G\3G\3G"+
|
||||
"\3G\3G\3G\3H\3H\3H\3H\3H\3I\3I\3I\3I\3I\3I\3I\3I\3J\3J\3J\3J\3K\3K\3K"+
|
||||
"\3K\3K\3K\3K\3L\3L\3L\3M\3M\3M\3N\3N\3N\3N\3O\3O\3O\3O\3O\3O\3P\3P\3Q"+
|
||||
"\3Q\3R\3R\3R\3R\3R\3R\3R\5R\u02b0\nR\3S\3S\3T\3T\3T\3U\3U\3V\3V\3V\3W"+
|
||||
"\3W\3X\3X\3Y\3Y\3Z\3Z\3[\3[\3\\\3\\\3\\\3]\3]\3^\3^\3_\3_\3_\3_\7_\u02d1"+
|
||||
"\n_\f_\16_\u02d4\13_\3_\3_\3`\6`\u02d9\n`\r`\16`\u02da\3a\6a\u02de\na"+
|
||||
"\ra\16a\u02df\3a\3a\7a\u02e4\na\fa\16a\u02e7\13a\3a\3a\6a\u02eb\na\ra"+
|
||||
"\16a\u02ec\3a\6a\u02f0\na\ra\16a\u02f1\3a\3a\7a\u02f6\na\fa\16a\u02f9"+
|
||||
"\13a\5a\u02fb\na\3a\3a\3a\3a\6a\u0301\na\ra\16a\u0302\3a\3a\5a\u0307\n"+
|
||||
"a\3b\3b\5b\u030b\nb\3b\3b\3b\7b\u0310\nb\fb\16b\u0313\13b\3c\3c\3c\3c"+
|
||||
"\6c\u0319\nc\rc\16c\u031a\3d\3d\3d\6d\u0320\nd\rd\16d\u0321\3e\3e\3e\3"+
|
||||
"e\7e\u0328\ne\fe\16e\u032b\13e\3e\3e\3f\3f\3f\3f\7f\u0333\nf\ff\16f\u0336"+
|
||||
"\13f\3f\3f\3g\3g\5g\u033c\ng\3g\6g\u033f\ng\rg\16g\u0340\3h\3h\3i\3i\3"+
|
||||
"j\3j\3j\3j\7j\u034b\nj\fj\16j\u034e\13j\3j\5j\u0351\nj\3j\5j\u0354\nj"+
|
||||
"\3j\3j\3k\3k\3k\3k\3k\7k\u035d\nk\fk\16k\u0360\13k\3k\3k\3k\3k\3k\3l\6"+
|
||||
"l\u0368\nl\rl\16l\u0369\3l\3l\3m\3m\3\u035e\2n\3\3\5\4\7\5\t\6\13\7\r"+
|
||||
"\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25"+
|
||||
")\26+\27-\30/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O"+
|
||||
")Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081"+
|
||||
"B\u0083C\u0085D\u0087E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095"+
|
||||
"L\u0097M\u0099N\u009bO\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9"+
|
||||
"V\u00abW\u00adX\u00afY\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd"+
|
||||
"`\u00bfa\u00c1b\u00c3c\u00c5d\u00c7e\u00c9f\u00cbg\u00cd\2\u00cf\2\u00d1"+
|
||||
"\2\u00d3h\u00d5i\u00d7j\u00d9k\3\2\f\3\2))\4\2BBaa\5\2<<BBaa\3\2$$\3\2"+
|
||||
"bb\4\2--//\3\2\62;\3\2C\\\4\2\f\f\17\17\5\2\13\f\17\17\"\"\u0390\2\3\3"+
|
||||
"k\4l\tl\4m\tm\4n\tn\4o\to\4p\tp\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3"+
|
||||
"\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\b"+
|
||||
"\3\b\3\b\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\13\3\f\3\f\3\f\3"+
|
||||
"\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\17\3\17\3\17\3\17"+
|
||||
"\3\17\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\21"+
|
||||
"\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\23\3\23"+
|
||||
"\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25"+
|
||||
"\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\26\3\27"+
|
||||
"\3\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\30"+
|
||||
"\3\30\3\30\3\30\3\31\3\31\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32"+
|
||||
"\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\34\3\34"+
|
||||
"\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\35\3\36\3\36\3\36\3\36"+
|
||||
"\3\36\3\36\3\36\3\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 \3!\3!\3!\3!\3"+
|
||||
"!\3!\3!\3!\3!\3!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3#\3#\3#\3#\3#\3"+
|
||||
"#\3$\3$\3$\3$\3$\3$\3$\3%\3%\3%\3&\3&\3&\3&\3&\3&\3\'\3\'\3\'\3(\3(\3"+
|
||||
"(\3(\3(\3)\3)\3)\3)\3)\3*\3*\3*\3*\3*\3+\3+\3+\3+\3+\3,\3,\3,\3,\3,\3"+
|
||||
",\3-\3-\3-\3-\3-\3-\3-\3.\3.\3.\3.\3.\3.\3/\3/\3/\3/\3/\3/\3/\3/\3\60"+
|
||||
"\3\60\3\60\3\60\3\61\3\61\3\61\3\61\3\61\3\62\3\62\3\62\3\62\3\62\3\62"+
|
||||
"\3\63\3\63\3\63\3\64\3\64\3\64\3\64\3\64\3\64\3\64\3\64\3\64\3\64\3\65"+
|
||||
"\3\65\3\65\3\66\3\66\3\66\3\66\3\66\3\66\3\67\3\67\3\67\3\67\3\67\3\67"+
|
||||
"\38\38\38\38\38\38\38\39\39\39\39\39\39\39\39\39\3:\3:\3:\3:\3:\3;\3;"+
|
||||
"\3;\3;\3;\3;\3<\3<\3<\3<\3<\3<\3=\3=\3=\3=\3=\3=\3>\3>\3>\3>\3>\3>\3>"+
|
||||
"\3>\3?\3?\3?\3?\3?\3?\3?\3@\3@\3@\3@\3@\3A\3A\3A\3A\3B\3B\3B\3B\3B\3B"+
|
||||
"\3C\3C\3C\3C\3C\3C\3C\3D\3D\3D\3D\3D\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3G"+
|
||||
"\3G\3G\3G\3G\3G\3H\3H\3H\3H\3H\3H\3I\3I\3I\3I\3I\3I\3I\3J\3J\3J\3J\3J"+
|
||||
"\3J\3K\3K\3K\3K\3K\3L\3L\3L\3L\3L\3L\3L\3L\3M\3M\3M\3M\3N\3N\3N\3N\3N"+
|
||||
"\3N\3N\3O\3O\3O\3P\3P\3P\3Q\3Q\3Q\3Q\3R\3R\3R\3R\3R\3R\3S\3S\3T\3T\3U"+
|
||||
"\3U\3U\3U\3U\3U\3U\5U\u02c7\nU\3V\3V\3W\3W\3W\3X\3X\3Y\3Y\3Y\3Z\3Z\3["+
|
||||
"\3[\3\\\3\\\3]\3]\3^\3^\3_\3_\3_\3`\3`\3a\3a\3b\3b\3b\3b\7b\u02e8\nb\f"+
|
||||
"b\16b\u02eb\13b\3b\3b\3c\6c\u02f0\nc\rc\16c\u02f1\3d\6d\u02f5\nd\rd\16"+
|
||||
"d\u02f6\3d\3d\7d\u02fb\nd\fd\16d\u02fe\13d\3d\3d\6d\u0302\nd\rd\16d\u0303"+
|
||||
"\3d\6d\u0307\nd\rd\16d\u0308\3d\3d\7d\u030d\nd\fd\16d\u0310\13d\5d\u0312"+
|
||||
"\nd\3d\3d\3d\3d\6d\u0318\nd\rd\16d\u0319\3d\3d\5d\u031e\nd\3e\3e\5e\u0322"+
|
||||
"\ne\3e\3e\3e\7e\u0327\ne\fe\16e\u032a\13e\3f\3f\3f\3f\6f\u0330\nf\rf\16"+
|
||||
"f\u0331\3g\3g\3g\6g\u0337\ng\rg\16g\u0338\3h\3h\3h\3h\7h\u033f\nh\fh\16"+
|
||||
"h\u0342\13h\3h\3h\3i\3i\3i\3i\7i\u034a\ni\fi\16i\u034d\13i\3i\3i\3j\3"+
|
||||
"j\5j\u0353\nj\3j\6j\u0356\nj\rj\16j\u0357\3k\3k\3l\3l\3m\3m\3m\3m\7m\u0362"+
|
||||
"\nm\fm\16m\u0365\13m\3m\5m\u0368\nm\3m\5m\u036b\nm\3m\3m\3n\3n\3n\3n\3"+
|
||||
"n\7n\u0374\nn\fn\16n\u0377\13n\3n\3n\3n\3n\3n\3o\6o\u037f\no\ro\16o\u0380"+
|
||||
"\3o\3o\3p\3p\3\u0375\2q\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f"+
|
||||
"\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63"+
|
||||
"\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62"+
|
||||
"c\63e\64g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083C\u0085D\u0087"+
|
||||
"E\u0089F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009b"+
|
||||
"O\u009dP\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00af"+
|
||||
"Y\u00b1Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bfa\u00c1b\u00c3"+
|
||||
"c\u00c5d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1j\u00d3\2\u00d5\2\u00d7"+
|
||||
"\2\u00d9k\u00dbl\u00ddm\u00dfn\3\2\f\3\2))\4\2BBaa\5\2<<BBaa\3\2$$\3\2"+
|
||||
"bb\4\2--//\3\2\62;\3\2C\\\4\2\f\f\17\17\5\2\13\f\17\17\"\"\u03a7\2\3\3"+
|
||||
"\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2"+
|
||||
"\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3"+
|
||||
"\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2"+
|
||||
@ -220,225 +222,231 @@ class SqlBaseLexer extends Lexer {
|
||||
"\3\2\2\2\2\u00ab\3\2\2\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2"+
|
||||
"\2\2\u00b3\3\2\2\2\2\u00b5\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb"+
|
||||
"\3\2\2\2\2\u00bd\3\2\2\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2"+
|
||||
"\2\2\u00c5\3\2\2\2\2\u00c7\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00d3"+
|
||||
"\3\2\2\2\2\u00d5\3\2\2\2\2\u00d7\3\2\2\2\2\u00d9\3\2\2\2\3\u00db\3\2\2"+
|
||||
"\2\5\u00dd\3\2\2\2\7\u00df\3\2\2\2\t\u00e1\3\2\2\2\13\u00e3\3\2\2\2\r"+
|
||||
"\u00e7\3\2\2\2\17\u00ef\3\2\2\2\21\u00f8\3\2\2\2\23\u00fc\3\2\2\2\25\u0100"+
|
||||
"\3\2\2\2\27\u0103\3\2\2\2\31\u0107\3\2\2\2\33\u010f\3\2\2\2\35\u0112\3"+
|
||||
"\2\2\2\37\u0117\3\2\2\2!\u011f\3\2\2\2#\u0128\3\2\2\2%\u0130\3\2\2\2\'"+
|
||||
"\u0136\3\2\2\2)\u013b\3\2\2\2+\u0144\3\2\2\2-\u014d\3\2\2\2/\u0154\3\2"+
|
||||
"\2\2\61\u015f\3\2\2\2\63\u0166\3\2\2\2\65\u016e\3\2\2\2\67\u0176\3\2\2"+
|
||||
"\29\u017c\3\2\2\2;\u0183\3\2\2\2=\u0188\3\2\2\2?\u018d\3\2\2\2A\u0197"+
|
||||
"\3\2\2\2C\u01a0\3\2\2\2E\u01a6\3\2\2\2G\u01ad\3\2\2\2I\u01b0\3\2\2\2K"+
|
||||
"\u01b6\3\2\2\2M\u01b9\3\2\2\2O\u01be\3\2\2\2Q\u01c3\3\2\2\2S\u01c8\3\2"+
|
||||
"\2\2U\u01ce\3\2\2\2W\u01d5\3\2\2\2Y\u01db\3\2\2\2[\u01e3\3\2\2\2]\u01e7"+
|
||||
"\3\2\2\2_\u01ec\3\2\2\2a\u01ef\3\2\2\2c\u01f9\3\2\2\2e\u01fc\3\2\2\2g"+
|
||||
"\u0202\3\2\2\2i\u0208\3\2\2\2k\u020f\3\2\2\2m\u0218\3\2\2\2o\u021d\3\2"+
|
||||
"\2\2q\u0223\3\2\2\2s\u0229\3\2\2\2u\u022f\3\2\2\2w\u0237\3\2\2\2y\u023e"+
|
||||
"\3\2\2\2{\u0243\3\2\2\2}\u0247\3\2\2\2\177\u024d\3\2\2\2\u0081\u0254\3"+
|
||||
"\2\2\2\u0083\u0259\3\2\2\2\u0085\u025e\3\2\2\2\u0087\u0263\3\2\2\2\u0089"+
|
||||
"\u0269\3\2\2\2\u008b\u026f\3\2\2\2\u008d\u0276\3\2\2\2\u008f\u027c\3\2"+
|
||||
"\2\2\u0091\u0281\3\2\2\2\u0093\u0289\3\2\2\2\u0095\u028d\3\2\2\2\u0097"+
|
||||
"\u0294\3\2\2\2\u0099\u0297\3\2\2\2\u009b\u029a\3\2\2\2\u009d\u029e\3\2"+
|
||||
"\2\2\u009f\u02a4\3\2\2\2\u00a1\u02a6\3\2\2\2\u00a3\u02af\3\2\2\2\u00a5"+
|
||||
"\u02b1\3\2\2\2\u00a7\u02b3\3\2\2\2\u00a9\u02b6\3\2\2\2\u00ab\u02b8\3\2"+
|
||||
"\2\2\u00ad\u02bb\3\2\2\2\u00af\u02bd\3\2\2\2\u00b1\u02bf\3\2\2\2\u00b3"+
|
||||
"\u02c1\3\2\2\2\u00b5\u02c3\3\2\2\2\u00b7\u02c5\3\2\2\2\u00b9\u02c8\3\2"+
|
||||
"\2\2\u00bb\u02ca\3\2\2\2\u00bd\u02cc\3\2\2\2\u00bf\u02d8\3\2\2\2\u00c1"+
|
||||
"\u0306\3\2\2\2\u00c3\u030a\3\2\2\2\u00c5\u0314\3\2\2\2\u00c7\u031f\3\2"+
|
||||
"\2\2\u00c9\u0323\3\2\2\2\u00cb\u032e\3\2\2\2\u00cd\u0339\3\2\2\2\u00cf"+
|
||||
"\u0342\3\2\2\2\u00d1\u0344\3\2\2\2\u00d3\u0346\3\2\2\2\u00d5\u0357\3\2"+
|
||||
"\2\2\u00d7\u0367\3\2\2\2\u00d9\u036d\3\2\2\2\u00db\u00dc\7*\2\2\u00dc"+
|
||||
"\4\3\2\2\2\u00dd\u00de\7+\2\2\u00de\6\3\2\2\2\u00df\u00e0\7.\2\2\u00e0"+
|
||||
"\b\3\2\2\2\u00e1\u00e2\7<\2\2\u00e2\n\3\2\2\2\u00e3\u00e4\7C\2\2\u00e4"+
|
||||
"\u00e5\7N\2\2\u00e5\u00e6\7N\2\2\u00e6\f\3\2\2\2\u00e7\u00e8\7C\2\2\u00e8"+
|
||||
"\u00e9\7P\2\2\u00e9\u00ea\7C\2\2\u00ea\u00eb\7N\2\2\u00eb\u00ec\7[\2\2"+
|
||||
"\u00ec\u00ed\7\\\2\2\u00ed\u00ee\7G\2\2\u00ee\16\3\2\2\2\u00ef\u00f0\7"+
|
||||
"C\2\2\u00f0\u00f1\7P\2\2\u00f1\u00f2\7C\2\2\u00f2\u00f3\7N\2\2\u00f3\u00f4"+
|
||||
"\7[\2\2\u00f4\u00f5\7\\\2\2\u00f5\u00f6\7G\2\2\u00f6\u00f7\7F\2\2\u00f7"+
|
||||
"\20\3\2\2\2\u00f8\u00f9\7C\2\2\u00f9\u00fa\7P\2\2\u00fa\u00fb\7F\2\2\u00fb"+
|
||||
"\22\3\2\2\2\u00fc\u00fd\7C\2\2\u00fd\u00fe\7P\2\2\u00fe\u00ff\7[\2\2\u00ff"+
|
||||
"\24\3\2\2\2\u0100\u0101\7C\2\2\u0101\u0102\7U\2\2\u0102\26\3\2\2\2\u0103"+
|
||||
"\u0104\7C\2\2\u0104\u0105\7U\2\2\u0105\u0106\7E\2\2\u0106\30\3\2\2\2\u0107"+
|
||||
"\u0108\7D\2\2\u0108\u0109\7G\2\2\u0109\u010a\7V\2\2\u010a\u010b\7Y\2\2"+
|
||||
"\u010b\u010c\7G\2\2\u010c\u010d\7G\2\2\u010d\u010e\7P\2\2\u010e\32\3\2"+
|
||||
"\2\2\u010f\u0110\7D\2\2\u0110\u0111\7[\2\2\u0111\34\3\2\2\2\u0112\u0113"+
|
||||
"\7E\2\2\u0113\u0114\7C\2\2\u0114\u0115\7U\2\2\u0115\u0116\7V\2\2\u0116"+
|
||||
"\36\3\2\2\2\u0117\u0118\7E\2\2\u0118\u0119\7C\2\2\u0119\u011a\7V\2\2\u011a"+
|
||||
"\u011b\7C\2\2\u011b\u011c\7N\2\2\u011c\u011d\7Q\2\2\u011d\u011e\7I\2\2"+
|
||||
"\u011e \3\2\2\2\u011f\u0120\7E\2\2\u0120\u0121\7C\2\2\u0121\u0122\7V\2"+
|
||||
"\2\u0122\u0123\7C\2\2\u0123\u0124\7N\2\2\u0124\u0125\7Q\2\2\u0125\u0126"+
|
||||
"\7I\2\2\u0126\u0127\7U\2\2\u0127\"\3\2\2\2\u0128\u0129\7E\2\2\u0129\u012a"+
|
||||
"\7Q\2\2\u012a\u012b\7N\2\2\u012b\u012c\7W\2\2\u012c\u012d\7O\2\2\u012d"+
|
||||
"\u012e\7P\2\2\u012e\u012f\7U\2\2\u012f$\3\2\2\2\u0130\u0131\7F\2\2\u0131"+
|
||||
"\u0132\7G\2\2\u0132\u0133\7D\2\2\u0133\u0134\7W\2\2\u0134\u0135\7I\2\2"+
|
||||
"\u0135&\3\2\2\2\u0136\u0137\7F\2\2\u0137\u0138\7G\2\2\u0138\u0139\7U\2"+
|
||||
"\2\u0139\u013a\7E\2\2\u013a(\3\2\2\2\u013b\u013c\7F\2\2\u013c\u013d\7"+
|
||||
"G\2\2\u013d\u013e\7U\2\2\u013e\u013f\7E\2\2\u013f\u0140\7T\2\2\u0140\u0141"+
|
||||
"\7K\2\2\u0141\u0142\7D\2\2\u0142\u0143\7G\2\2\u0143*\3\2\2\2\u0144\u0145"+
|
||||
"\7F\2\2\u0145\u0146\7K\2\2\u0146\u0147\7U\2\2\u0147\u0148\7V\2\2\u0148"+
|
||||
"\u0149\7K\2\2\u0149\u014a\7P\2\2\u014a\u014b\7E\2\2\u014b\u014c\7V\2\2"+
|
||||
"\u014c,\3\2\2\2\u014d\u014e\7G\2\2\u014e\u014f\7U\2\2\u014f\u0150\7E\2"+
|
||||
"\2\u0150\u0151\7C\2\2\u0151\u0152\7R\2\2\u0152\u0153\7G\2\2\u0153.\3\2"+
|
||||
"\2\2\u0154\u0155\7G\2\2\u0155\u0156\7Z\2\2\u0156\u0157\7G\2\2\u0157\u0158"+
|
||||
"\7E\2\2\u0158\u0159\7W\2\2\u0159\u015a\7V\2\2\u015a\u015b\7C\2\2\u015b"+
|
||||
"\u015c\7D\2\2\u015c\u015d\7N\2\2\u015d\u015e\7G\2\2\u015e\60\3\2\2\2\u015f"+
|
||||
"\u0160\7G\2\2\u0160\u0161\7Z\2\2\u0161\u0162\7K\2\2\u0162\u0163\7U\2\2"+
|
||||
"\u0163\u0164\7V\2\2\u0164\u0165\7U\2\2\u0165\62\3\2\2\2\u0166\u0167\7"+
|
||||
"G\2\2\u0167\u0168\7Z\2\2\u0168\u0169\7R\2\2\u0169\u016a\7N\2\2\u016a\u016b"+
|
||||
"\7C\2\2\u016b\u016c\7K\2\2\u016c\u016d\7P\2\2\u016d\64\3\2\2\2\u016e\u016f"+
|
||||
"\7G\2\2\u016f\u0170\7Z\2\2\u0170\u0171\7V\2\2\u0171\u0172\7T\2\2\u0172"+
|
||||
"\u0173\7C\2\2\u0173\u0174\7E\2\2\u0174\u0175\7V\2\2\u0175\66\3\2\2\2\u0176"+
|
||||
"\u0177\7H\2\2\u0177\u0178\7C\2\2\u0178\u0179\7N\2\2\u0179\u017a\7U\2\2"+
|
||||
"\u017a\u017b\7G\2\2\u017b8\3\2\2\2\u017c\u017d\7H\2\2\u017d\u017e\7Q\2"+
|
||||
"\2\u017e\u017f\7T\2\2\u017f\u0180\7O\2\2\u0180\u0181\7C\2\2\u0181\u0182"+
|
||||
"\7V\2\2\u0182:\3\2\2\2\u0183\u0184\7H\2\2\u0184\u0185\7T\2\2\u0185\u0186"+
|
||||
"\7Q\2\2\u0186\u0187\7O\2\2\u0187<\3\2\2\2\u0188\u0189\7H\2\2\u0189\u018a"+
|
||||
"\7W\2\2\u018a\u018b\7N\2\2\u018b\u018c\7N\2\2\u018c>\3\2\2\2\u018d\u018e"+
|
||||
"\7H\2\2\u018e\u018f\7W\2\2\u018f\u0190\7P\2\2\u0190\u0191\7E\2\2\u0191"+
|
||||
"\u0192\7V\2\2\u0192\u0193\7K\2\2\u0193\u0194\7Q\2\2\u0194\u0195\7P\2\2"+
|
||||
"\u0195\u0196\7U\2\2\u0196@\3\2\2\2\u0197\u0198\7I\2\2\u0198\u0199\7T\2"+
|
||||
"\2\u0199\u019a\7C\2\2\u019a\u019b\7R\2\2\u019b\u019c\7J\2\2\u019c\u019d"+
|
||||
"\7X\2\2\u019d\u019e\7K\2\2\u019e\u019f\7\\\2\2\u019fB\3\2\2\2\u01a0\u01a1"+
|
||||
"\7I\2\2\u01a1\u01a2\7T\2\2\u01a2\u01a3\7Q\2\2\u01a3\u01a4\7W\2\2\u01a4"+
|
||||
"\u01a5\7R\2\2\u01a5D\3\2\2\2\u01a6\u01a7\7J\2\2\u01a7\u01a8\7C\2\2\u01a8"+
|
||||
"\u01a9\7X\2\2\u01a9\u01aa\7K\2\2\u01aa\u01ab\7P\2\2\u01ab\u01ac\7I\2\2"+
|
||||
"\u01acF\3\2\2\2\u01ad\u01ae\7K\2\2\u01ae\u01af\7P\2\2\u01afH\3\2\2\2\u01b0"+
|
||||
"\u01b1\7K\2\2\u01b1\u01b2\7P\2\2\u01b2\u01b3\7P\2\2\u01b3\u01b4\7G\2\2"+
|
||||
"\u01b4\u01b5\7T\2\2\u01b5J\3\2\2\2\u01b6\u01b7\7K\2\2\u01b7\u01b8\7U\2"+
|
||||
"\2\u01b8L\3\2\2\2\u01b9\u01ba\7L\2\2\u01ba\u01bb\7Q\2\2\u01bb\u01bc\7"+
|
||||
"K\2\2\u01bc\u01bd\7P\2\2\u01bdN\3\2\2\2\u01be\u01bf\7N\2\2\u01bf\u01c0"+
|
||||
"\7G\2\2\u01c0\u01c1\7H\2\2\u01c1\u01c2\7V\2\2\u01c2P\3\2\2\2\u01c3\u01c4"+
|
||||
"\7N\2\2\u01c4\u01c5\7K\2\2\u01c5\u01c6\7M\2\2\u01c6\u01c7\7G\2\2\u01c7"+
|
||||
"R\3\2\2\2\u01c8\u01c9\7N\2\2\u01c9\u01ca\7K\2\2\u01ca\u01cb\7O\2\2\u01cb"+
|
||||
"\u01cc\7K\2\2\u01cc\u01cd\7V\2\2\u01cdT\3\2\2\2\u01ce\u01cf\7O\2\2\u01cf"+
|
||||
"\u01d0\7C\2\2\u01d0\u01d1\7R\2\2\u01d1\u01d2\7R\2\2\u01d2\u01d3\7G\2\2"+
|
||||
"\u01d3\u01d4\7F\2\2\u01d4V\3\2\2\2\u01d5\u01d6\7O\2\2\u01d6\u01d7\7C\2"+
|
||||
"\2\u01d7\u01d8\7V\2\2\u01d8\u01d9\7E\2\2\u01d9\u01da\7J\2\2\u01daX\3\2"+
|
||||
"\2\2\u01db\u01dc\7P\2\2\u01dc\u01dd\7C\2\2\u01dd\u01de\7V\2\2\u01de\u01df"+
|
||||
"\7W\2\2\u01df\u01e0\7T\2\2\u01e0\u01e1\7C\2\2\u01e1\u01e2\7N\2\2\u01e2"+
|
||||
"Z\3\2\2\2\u01e3\u01e4\7P\2\2\u01e4\u01e5\7Q\2\2\u01e5\u01e6\7V\2\2\u01e6"+
|
||||
"\\\3\2\2\2\u01e7\u01e8\7P\2\2\u01e8\u01e9\7W\2\2\u01e9\u01ea\7N\2\2\u01ea"+
|
||||
"\u01eb\7N\2\2\u01eb^\3\2\2\2\u01ec\u01ed\7Q\2\2\u01ed\u01ee\7P\2\2\u01ee"+
|
||||
"`\3\2\2\2\u01ef\u01f0\7Q\2\2\u01f0\u01f1\7R\2\2\u01f1\u01f2\7V\2\2\u01f2"+
|
||||
"\u01f3\7K\2\2\u01f3\u01f4\7O\2\2\u01f4\u01f5\7K\2\2\u01f5\u01f6\7\\\2"+
|
||||
"\2\u01f6\u01f7\7G\2\2\u01f7\u01f8\7F\2\2\u01f8b\3\2\2\2\u01f9\u01fa\7"+
|
||||
"Q\2\2\u01fa\u01fb\7T\2\2\u01fbd\3\2\2\2\u01fc\u01fd\7Q\2\2\u01fd\u01fe"+
|
||||
"\7T\2\2\u01fe\u01ff\7F\2\2\u01ff\u0200\7G\2\2\u0200\u0201\7T\2\2\u0201"+
|
||||
"f\3\2\2\2\u0202\u0203\7Q\2\2\u0203\u0204\7W\2\2\u0204\u0205\7V\2\2\u0205"+
|
||||
"\u0206\7G\2\2\u0206\u0207\7T\2\2\u0207h\3\2\2\2\u0208\u0209\7R\2\2\u0209"+
|
||||
"\u020a\7C\2\2\u020a\u020b\7T\2\2\u020b\u020c\7U\2\2\u020c\u020d\7G\2\2"+
|
||||
"\u020d\u020e\7F\2\2\u020ej\3\2\2\2\u020f\u0210\7R\2\2\u0210\u0211\7J\2"+
|
||||
"\2\u0211\u0212\7[\2\2\u0212\u0213\7U\2\2\u0213\u0214\7K\2\2\u0214\u0215"+
|
||||
"\7E\2\2\u0215\u0216\7C\2\2\u0216\u0217\7N\2\2\u0217l\3\2\2\2\u0218\u0219"+
|
||||
"\7R\2\2\u0219\u021a\7N\2\2\u021a\u021b\7C\2\2\u021b\u021c\7P\2\2\u021c"+
|
||||
"n\3\2\2\2\u021d\u021e\7T\2\2\u021e\u021f\7K\2\2\u021f\u0220\7I\2\2\u0220"+
|
||||
"\u0221\7J\2\2\u0221\u0222\7V\2\2\u0222p\3\2\2\2\u0223\u0224\7T\2\2\u0224"+
|
||||
"\u0225\7N\2\2\u0225\u0226\7K\2\2\u0226\u0227\7M\2\2\u0227\u0228\7G\2\2"+
|
||||
"\u0228r\3\2\2\2\u0229\u022a\7S\2\2\u022a\u022b\7W\2\2\u022b\u022c\7G\2"+
|
||||
"\2\u022c\u022d\7T\2\2\u022d\u022e\7[\2\2\u022et\3\2\2\2\u022f\u0230\7"+
|
||||
"U\2\2\u0230\u0231\7E\2\2\u0231\u0232\7J\2\2\u0232\u0233\7G\2\2\u0233\u0234"+
|
||||
"\7O\2\2\u0234\u0235\7C\2\2\u0235\u0236\7U\2\2\u0236v\3\2\2\2\u0237\u0238"+
|
||||
"\7U\2\2\u0238\u0239\7G\2\2\u0239\u023a\7N\2\2\u023a\u023b\7G\2\2\u023b"+
|
||||
"\u023c\7E\2\2\u023c\u023d\7V\2\2\u023dx\3\2\2\2\u023e\u023f\7U\2\2\u023f"+
|
||||
"\u0240\7J\2\2\u0240\u0241\7Q\2\2\u0241\u0242\7Y\2\2\u0242z\3\2\2\2\u0243"+
|
||||
"\u0244\7U\2\2\u0244\u0245\7[\2\2\u0245\u0246\7U\2\2\u0246|\3\2\2\2\u0247"+
|
||||
"\u0248\7V\2\2\u0248\u0249\7C\2\2\u0249\u024a\7D\2\2\u024a\u024b\7N\2\2"+
|
||||
"\u024b\u024c\7G\2\2\u024c~\3\2\2\2\u024d\u024e\7V\2\2\u024e\u024f\7C\2"+
|
||||
"\2\u024f\u0250\7D\2\2\u0250\u0251\7N\2\2\u0251\u0252\7G\2\2\u0252\u0253"+
|
||||
"\7U\2\2\u0253\u0080\3\2\2\2\u0254\u0255\7V\2\2\u0255\u0256\7G\2\2\u0256"+
|
||||
"\u0257\7Z\2\2\u0257\u0258\7V\2\2\u0258\u0082\3\2\2\2\u0259\u025a\7V\2"+
|
||||
"\2\u025a\u025b\7T\2\2\u025b\u025c\7W\2\2\u025c\u025d\7G\2\2\u025d\u0084"+
|
||||
"\3\2\2\2\u025e\u025f\7V\2\2\u025f\u0260\7[\2\2\u0260\u0261\7R\2\2\u0261"+
|
||||
"\u0262\7G\2\2\u0262\u0086\3\2\2\2\u0263\u0264\7V\2\2\u0264\u0265\7[\2"+
|
||||
"\2\u0265\u0266\7R\2\2\u0266\u0267\7G\2\2\u0267\u0268\7U\2\2\u0268\u0088"+
|
||||
"\3\2\2\2\u0269\u026a\7W\2\2\u026a\u026b\7U\2\2\u026b\u026c\7K\2\2\u026c"+
|
||||
"\u026d\7P\2\2\u026d\u026e\7I\2\2\u026e\u008a\3\2\2\2\u026f\u0270\7X\2"+
|
||||
"\2\u0270\u0271\7G\2\2\u0271\u0272\7T\2\2\u0272\u0273\7K\2\2\u0273\u0274"+
|
||||
"\7H\2\2\u0274\u0275\7[\2\2\u0275\u008c\3\2\2\2\u0276\u0277\7Y\2\2\u0277"+
|
||||
"\u0278\7J\2\2\u0278\u0279\7G\2\2\u0279\u027a\7T\2\2\u027a\u027b\7G\2\2"+
|
||||
"\u027b\u008e\3\2\2\2\u027c\u027d\7Y\2\2\u027d\u027e\7K\2\2\u027e\u027f"+
|
||||
"\7V\2\2\u027f\u0280\7J\2\2\u0280\u0090\3\2\2\2\u0281\u0282\7}\2\2\u0282"+
|
||||
"\u0283\7G\2\2\u0283\u0284\7U\2\2\u0284\u0285\7E\2\2\u0285\u0286\7C\2\2"+
|
||||
"\u0286\u0287\7R\2\2\u0287\u0288\7G\2\2\u0288\u0092\3\2\2\2\u0289\u028a"+
|
||||
"\7}\2\2\u028a\u028b\7H\2\2\u028b\u028c\7P\2\2\u028c\u0094\3\2\2\2\u028d"+
|
||||
"\u028e\7}\2\2\u028e\u028f\7N\2\2\u028f\u0290\7K\2\2\u0290\u0291\7O\2\2"+
|
||||
"\u0291\u0292\7K\2\2\u0292\u0293\7V\2\2\u0293\u0096\3\2\2\2\u0294\u0295"+
|
||||
"\7}\2\2\u0295\u0296\7F\2\2\u0296\u0098\3\2\2\2\u0297\u0298\7}\2\2\u0298"+
|
||||
"\u0299\7V\2\2\u0299\u009a\3\2\2\2\u029a\u029b\7}\2\2\u029b\u029c\7V\2"+
|
||||
"\2\u029c\u029d\7U\2\2\u029d\u009c\3\2\2\2\u029e\u029f\7}\2\2\u029f\u02a0"+
|
||||
"\7I\2\2\u02a0\u02a1\7W\2\2\u02a1\u02a2\7K\2\2\u02a2\u02a3\7F\2\2\u02a3"+
|
||||
"\u009e\3\2\2\2\u02a4\u02a5\7\177\2\2\u02a5\u00a0\3\2\2\2\u02a6\u02a7\7"+
|
||||
"?\2\2\u02a7\u00a2\3\2\2\2\u02a8\u02a9\7>\2\2\u02a9\u02b0\7@\2\2\u02aa"+
|
||||
"\u02ab\7#\2\2\u02ab\u02b0\7?\2\2\u02ac\u02ad\7>\2\2\u02ad\u02ae\7?\2\2"+
|
||||
"\u02ae\u02b0\7@\2\2\u02af\u02a8\3\2\2\2\u02af\u02aa\3\2\2\2\u02af\u02ac"+
|
||||
"\3\2\2\2\u02b0\u00a4\3\2\2\2\u02b1\u02b2\7>\2\2\u02b2\u00a6\3\2\2\2\u02b3"+
|
||||
"\u02b4\7>\2\2\u02b4\u02b5\7?\2\2\u02b5\u00a8\3\2\2\2\u02b6\u02b7\7@\2"+
|
||||
"\2\u02b7\u00aa\3\2\2\2\u02b8\u02b9\7@\2\2\u02b9\u02ba\7?\2\2\u02ba\u00ac"+
|
||||
"\3\2\2\2\u02bb\u02bc\7-\2\2\u02bc\u00ae\3\2\2\2\u02bd\u02be\7/\2\2\u02be"+
|
||||
"\u00b0\3\2\2\2\u02bf\u02c0\7,\2\2\u02c0\u00b2\3\2\2\2\u02c1\u02c2\7\61"+
|
||||
"\2\2\u02c2\u00b4\3\2\2\2\u02c3\u02c4\7\'\2\2\u02c4\u00b6\3\2\2\2\u02c5"+
|
||||
"\u02c6\7~\2\2\u02c6\u02c7\7~\2\2\u02c7\u00b8\3\2\2\2\u02c8\u02c9\7\60"+
|
||||
"\2\2\u02c9\u00ba\3\2\2\2\u02ca\u02cb\7A\2\2\u02cb\u00bc\3\2\2\2\u02cc"+
|
||||
"\u02d2\7)\2\2\u02cd\u02d1\n\2\2\2\u02ce\u02cf\7)\2\2\u02cf\u02d1\7)\2"+
|
||||
"\2\u02d0\u02cd\3\2\2\2\u02d0\u02ce\3\2\2\2\u02d1\u02d4\3\2\2\2\u02d2\u02d0"+
|
||||
"\3\2\2\2\u02d2\u02d3\3\2\2\2\u02d3\u02d5\3\2\2\2\u02d4\u02d2\3\2\2\2\u02d5"+
|
||||
"\u02d6\7)\2\2\u02d6\u00be\3\2\2\2\u02d7\u02d9\5\u00cfh\2\u02d8\u02d7\3"+
|
||||
"\2\2\2\u02d9\u02da\3\2\2\2\u02da\u02d8\3\2\2\2\u02da\u02db\3\2\2\2\u02db"+
|
||||
"\u00c0\3\2\2\2\u02dc\u02de\5\u00cfh\2\u02dd\u02dc\3\2\2\2\u02de\u02df"+
|
||||
"\3\2\2\2\u02df\u02dd\3\2\2\2\u02df\u02e0\3\2\2\2\u02e0\u02e1\3\2\2\2\u02e1"+
|
||||
"\u02e5\5\u00b9]\2\u02e2\u02e4\5\u00cfh\2\u02e3\u02e2\3\2\2\2\u02e4\u02e7"+
|
||||
"\3\2\2\2\u02e5\u02e3\3\2\2\2\u02e5\u02e6\3\2\2\2\u02e6\u0307\3\2\2\2\u02e7"+
|
||||
"\u02e5\3\2\2\2\u02e8\u02ea\5\u00b9]\2\u02e9\u02eb\5\u00cfh\2\u02ea\u02e9"+
|
||||
"\3\2\2\2\u02eb\u02ec\3\2\2\2\u02ec\u02ea\3\2\2\2\u02ec\u02ed\3\2\2\2\u02ed"+
|
||||
"\u0307\3\2\2\2\u02ee\u02f0\5\u00cfh\2\u02ef\u02ee\3\2\2\2\u02f0\u02f1"+
|
||||
"\3\2\2\2\u02f1\u02ef\3\2\2\2\u02f1\u02f2\3\2\2\2\u02f2\u02fa\3\2\2\2\u02f3"+
|
||||
"\u02f7\5\u00b9]\2\u02f4\u02f6\5\u00cfh\2\u02f5\u02f4\3\2\2\2\u02f6\u02f9"+
|
||||
"\3\2\2\2\u02f7\u02f5\3\2\2\2\u02f7\u02f8\3\2\2\2\u02f8\u02fb\3\2\2\2\u02f9"+
|
||||
"\u02f7\3\2\2\2\u02fa\u02f3\3\2\2\2\u02fa\u02fb\3\2\2\2\u02fb\u02fc\3\2"+
|
||||
"\2\2\u02fc\u02fd\5\u00cdg\2\u02fd\u0307\3\2\2\2\u02fe\u0300\5\u00b9]\2"+
|
||||
"\u02ff\u0301\5\u00cfh\2\u0300\u02ff\3\2\2\2\u0301\u0302\3\2\2\2\u0302"+
|
||||
"\u0300\3\2\2\2\u0302\u0303\3\2\2\2\u0303\u0304\3\2\2\2\u0304\u0305\5\u00cd"+
|
||||
"g\2\u0305\u0307\3\2\2\2\u0306\u02dd\3\2\2\2\u0306\u02e8\3\2\2\2\u0306"+
|
||||
"\u02ef\3\2\2\2\u0306\u02fe\3\2\2\2\u0307\u00c2\3\2\2\2\u0308\u030b\5\u00d1"+
|
||||
"i\2\u0309\u030b\7a\2\2\u030a\u0308\3\2\2\2\u030a\u0309\3\2\2\2\u030b\u0311"+
|
||||
"\3\2\2\2\u030c\u0310\5\u00d1i\2\u030d\u0310\5\u00cfh\2\u030e\u0310\t\3"+
|
||||
"\2\2\u030f\u030c\3\2\2\2\u030f\u030d\3\2\2\2\u030f\u030e\3\2\2\2\u0310"+
|
||||
"\u0313\3\2\2\2\u0311\u030f\3\2\2\2\u0311\u0312\3\2\2\2\u0312\u00c4\3\2"+
|
||||
"\2\2\u0313\u0311\3\2\2\2\u0314\u0318\5\u00cfh\2\u0315\u0319\5\u00d1i\2"+
|
||||
"\u0316\u0319\5\u00cfh\2\u0317\u0319\t\4\2\2\u0318\u0315\3\2\2\2\u0318"+
|
||||
"\u0316\3\2\2\2\u0318\u0317\3\2\2\2\u0319\u031a\3\2\2\2\u031a\u0318\3\2"+
|
||||
"\2\2\u031a\u031b\3\2\2\2\u031b\u00c6\3\2\2\2\u031c\u0320\5\u00d1i\2\u031d"+
|
||||
"\u0320\5\u00cfh\2\u031e\u0320\7a\2\2\u031f\u031c\3\2\2\2\u031f\u031d\3"+
|
||||
"\2\2\2\u031f\u031e\3\2\2\2\u0320\u0321\3\2\2\2\u0321\u031f\3\2\2\2\u0321"+
|
||||
"\u0322\3\2\2\2\u0322\u00c8\3\2\2\2\u0323\u0329\7$\2\2\u0324\u0328\n\5"+
|
||||
"\2\2\u0325\u0326\7$\2\2\u0326\u0328\7$\2\2\u0327\u0324\3\2\2\2\u0327\u0325"+
|
||||
"\3\2\2\2\u0328\u032b\3\2\2\2\u0329\u0327\3\2\2\2\u0329\u032a\3\2\2\2\u032a"+
|
||||
"\u032c\3\2\2\2\u032b\u0329\3\2\2\2\u032c\u032d\7$\2\2\u032d\u00ca\3\2"+
|
||||
"\2\2\u032e\u0334\7b\2\2\u032f\u0333\n\6\2\2\u0330\u0331\7b\2\2\u0331\u0333"+
|
||||
"\7b\2\2\u0332\u032f\3\2\2\2\u0332\u0330\3\2\2\2\u0333\u0336\3\2\2\2\u0334"+
|
||||
"\u0332\3\2\2\2\u0334\u0335\3\2\2\2\u0335\u0337\3\2\2\2\u0336\u0334\3\2"+
|
||||
"\2\2\u0337\u0338\7b\2\2\u0338\u00cc\3\2\2\2\u0339\u033b\7G\2\2\u033a\u033c"+
|
||||
"\t\7\2\2\u033b\u033a\3\2\2\2\u033b\u033c\3\2\2\2\u033c\u033e\3\2\2\2\u033d"+
|
||||
"\u033f\5\u00cfh\2\u033e\u033d\3\2\2\2\u033f\u0340\3\2\2\2\u0340\u033e"+
|
||||
"\3\2\2\2\u0340\u0341\3\2\2\2\u0341\u00ce\3\2\2\2\u0342\u0343\t\b\2\2\u0343"+
|
||||
"\u00d0\3\2\2\2\u0344\u0345\t\t\2\2\u0345\u00d2\3\2\2\2\u0346\u0347\7/"+
|
||||
"\2\2\u0347\u0348\7/\2\2\u0348\u034c\3\2\2\2\u0349\u034b\n\n\2\2\u034a"+
|
||||
"\u0349\3\2\2\2\u034b\u034e\3\2\2\2\u034c\u034a\3\2\2\2\u034c\u034d\3\2"+
|
||||
"\2\2\u034d\u0350\3\2\2\2\u034e\u034c\3\2\2\2\u034f\u0351\7\17\2\2\u0350"+
|
||||
"\u034f\3\2\2\2\u0350\u0351\3\2\2\2\u0351\u0353\3\2\2\2\u0352\u0354\7\f"+
|
||||
"\2\2\u0353\u0352\3\2\2\2\u0353\u0354\3\2\2\2\u0354\u0355\3\2\2\2\u0355"+
|
||||
"\u0356\bj\2\2\u0356\u00d4\3\2\2\2\u0357\u0358\7\61\2\2\u0358\u0359\7,"+
|
||||
"\2\2\u0359\u035e\3\2\2\2\u035a\u035d\5\u00d5k\2\u035b\u035d\13\2\2\2\u035c"+
|
||||
"\u035a\3\2\2\2\u035c\u035b\3\2\2\2\u035d\u0360\3\2\2\2\u035e\u035f\3\2"+
|
||||
"\2\2\u035e\u035c\3\2\2\2\u035f\u0361\3\2\2\2\u0360\u035e\3\2\2\2\u0361"+
|
||||
"\u0362\7,\2\2\u0362\u0363\7\61\2\2\u0363\u0364\3\2\2\2\u0364\u0365\bk"+
|
||||
"\2\2\u0365\u00d6\3\2\2\2\u0366\u0368\t\13\2\2\u0367\u0366\3\2\2\2\u0368"+
|
||||
"\u0369\3\2\2\2\u0369\u0367\3\2\2\2\u0369\u036a\3\2\2\2\u036a\u036b\3\2"+
|
||||
"\2\2\u036b\u036c\bl\2\2\u036c\u00d8\3\2\2\2\u036d\u036e\13\2\2\2\u036e"+
|
||||
"\u00da\3\2\2\2\"\2\u02af\u02d0\u02d2\u02da\u02df\u02e5\u02ec\u02f1\u02f7"+
|
||||
"\u02fa\u0302\u0306\u030a\u030f\u0311\u0318\u031a\u031f\u0321\u0327\u0329"+
|
||||
"\u0332\u0334\u033b\u0340\u034c\u0350\u0353\u035c\u035e\u0369\3\2\3\2";
|
||||
"\2\2\u00c5\3\2\2\2\2\u00c7\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd"+
|
||||
"\3\2\2\2\2\u00cf\3\2\2\2\2\u00d1\3\2\2\2\2\u00d9\3\2\2\2\2\u00db\3\2\2"+
|
||||
"\2\2\u00dd\3\2\2\2\2\u00df\3\2\2\2\3\u00e1\3\2\2\2\5\u00e3\3\2\2\2\7\u00e5"+
|
||||
"\3\2\2\2\t\u00e7\3\2\2\2\13\u00e9\3\2\2\2\r\u00ed\3\2\2\2\17\u00f5\3\2"+
|
||||
"\2\2\21\u00fe\3\2\2\2\23\u0102\3\2\2\2\25\u0106\3\2\2\2\27\u0109\3\2\2"+
|
||||
"\2\31\u010d\3\2\2\2\33\u0115\3\2\2\2\35\u0118\3\2\2\2\37\u011d\3\2\2\2"+
|
||||
"!\u0125\3\2\2\2#\u012e\3\2\2\2%\u0136\3\2\2\2\'\u013c\3\2\2\2)\u0141\3"+
|
||||
"\2\2\2+\u014a\3\2\2\2-\u0153\3\2\2\2/\u015a\3\2\2\2\61\u0165\3\2\2\2\63"+
|
||||
"\u016c\3\2\2\2\65\u0174\3\2\2\2\67\u017c\3\2\2\29\u0182\3\2\2\2;\u0188"+
|
||||
"\3\2\2\2=\u018f\3\2\2\2?\u0194\3\2\2\2A\u0199\3\2\2\2C\u01a3\3\2\2\2E"+
|
||||
"\u01ac\3\2\2\2G\u01b2\3\2\2\2I\u01b9\3\2\2\2K\u01bc\3\2\2\2M\u01c2\3\2"+
|
||||
"\2\2O\u01c5\3\2\2\2Q\u01ca\3\2\2\2S\u01cf\3\2\2\2U\u01d4\3\2\2\2W\u01d9"+
|
||||
"\3\2\2\2Y\u01df\3\2\2\2[\u01e6\3\2\2\2]\u01ec\3\2\2\2_\u01f4\3\2\2\2a"+
|
||||
"\u01f8\3\2\2\2c\u01fd\3\2\2\2e\u0203\3\2\2\2g\u0206\3\2\2\2i\u0210\3\2"+
|
||||
"\2\2k\u0213\3\2\2\2m\u0219\3\2\2\2o\u021f\3\2\2\2q\u0226\3\2\2\2s\u022f"+
|
||||
"\3\2\2\2u\u0234\3\2\2\2w\u023a\3\2\2\2y\u0240\3\2\2\2{\u0246\3\2\2\2}"+
|
||||
"\u024e\3\2\2\2\177\u0255\3\2\2\2\u0081\u025a\3\2\2\2\u0083\u025e\3\2\2"+
|
||||
"\2\u0085\u0264\3\2\2\2\u0087\u026b\3\2\2\2\u0089\u0270\3\2\2\2\u008b\u0275"+
|
||||
"\3\2\2\2\u008d\u027a\3\2\2\2\u008f\u0280\3\2\2\2\u0091\u0286\3\2\2\2\u0093"+
|
||||
"\u028d\3\2\2\2\u0095\u0293\3\2\2\2\u0097\u0298\3\2\2\2\u0099\u02a0\3\2"+
|
||||
"\2\2\u009b\u02a4\3\2\2\2\u009d\u02ab\3\2\2\2\u009f\u02ae\3\2\2\2\u00a1"+
|
||||
"\u02b1\3\2\2\2\u00a3\u02b5\3\2\2\2\u00a5\u02bb\3\2\2\2\u00a7\u02bd\3\2"+
|
||||
"\2\2\u00a9\u02c6\3\2\2\2\u00ab\u02c8\3\2\2\2\u00ad\u02ca\3\2\2\2\u00af"+
|
||||
"\u02cd\3\2\2\2\u00b1\u02cf\3\2\2\2\u00b3\u02d2\3\2\2\2\u00b5\u02d4\3\2"+
|
||||
"\2\2\u00b7\u02d6\3\2\2\2\u00b9\u02d8\3\2\2\2\u00bb\u02da\3\2\2\2\u00bd"+
|
||||
"\u02dc\3\2\2\2\u00bf\u02df\3\2\2\2\u00c1\u02e1\3\2\2\2\u00c3\u02e3\3\2"+
|
||||
"\2\2\u00c5\u02ef\3\2\2\2\u00c7\u031d\3\2\2\2\u00c9\u0321\3\2\2\2\u00cb"+
|
||||
"\u032b\3\2\2\2\u00cd\u0336\3\2\2\2\u00cf\u033a\3\2\2\2\u00d1\u0345\3\2"+
|
||||
"\2\2\u00d3\u0350\3\2\2\2\u00d5\u0359\3\2\2\2\u00d7\u035b\3\2\2\2\u00d9"+
|
||||
"\u035d\3\2\2\2\u00db\u036e\3\2\2\2\u00dd\u037e\3\2\2\2\u00df\u0384\3\2"+
|
||||
"\2\2\u00e1\u00e2\7*\2\2\u00e2\4\3\2\2\2\u00e3\u00e4\7+\2\2\u00e4\6\3\2"+
|
||||
"\2\2\u00e5\u00e6\7.\2\2\u00e6\b\3\2\2\2\u00e7\u00e8\7<\2\2\u00e8\n\3\2"+
|
||||
"\2\2\u00e9\u00ea\7C\2\2\u00ea\u00eb\7N\2\2\u00eb\u00ec\7N\2\2\u00ec\f"+
|
||||
"\3\2\2\2\u00ed\u00ee\7C\2\2\u00ee\u00ef\7P\2\2\u00ef\u00f0\7C\2\2\u00f0"+
|
||||
"\u00f1\7N\2\2\u00f1\u00f2\7[\2\2\u00f2\u00f3\7\\\2\2\u00f3\u00f4\7G\2"+
|
||||
"\2\u00f4\16\3\2\2\2\u00f5\u00f6\7C\2\2\u00f6\u00f7\7P\2\2\u00f7\u00f8"+
|
||||
"\7C\2\2\u00f8\u00f9\7N\2\2\u00f9\u00fa\7[\2\2\u00fa\u00fb\7\\\2\2\u00fb"+
|
||||
"\u00fc\7G\2\2\u00fc\u00fd\7F\2\2\u00fd\20\3\2\2\2\u00fe\u00ff\7C\2\2\u00ff"+
|
||||
"\u0100\7P\2\2\u0100\u0101\7F\2\2\u0101\22\3\2\2\2\u0102\u0103\7C\2\2\u0103"+
|
||||
"\u0104\7P\2\2\u0104\u0105\7[\2\2\u0105\24\3\2\2\2\u0106\u0107\7C\2\2\u0107"+
|
||||
"\u0108\7U\2\2\u0108\26\3\2\2\2\u0109\u010a\7C\2\2\u010a\u010b\7U\2\2\u010b"+
|
||||
"\u010c\7E\2\2\u010c\30\3\2\2\2\u010d\u010e\7D\2\2\u010e\u010f\7G\2\2\u010f"+
|
||||
"\u0110\7V\2\2\u0110\u0111\7Y\2\2\u0111\u0112\7G\2\2\u0112\u0113\7G\2\2"+
|
||||
"\u0113\u0114\7P\2\2\u0114\32\3\2\2\2\u0115\u0116\7D\2\2\u0116\u0117\7"+
|
||||
"[\2\2\u0117\34\3\2\2\2\u0118\u0119\7E\2\2\u0119\u011a\7C\2\2\u011a\u011b"+
|
||||
"\7U\2\2\u011b\u011c\7V\2\2\u011c\36\3\2\2\2\u011d\u011e\7E\2\2\u011e\u011f"+
|
||||
"\7C\2\2\u011f\u0120\7V\2\2\u0120\u0121\7C\2\2\u0121\u0122\7N\2\2\u0122"+
|
||||
"\u0123\7Q\2\2\u0123\u0124\7I\2\2\u0124 \3\2\2\2\u0125\u0126\7E\2\2\u0126"+
|
||||
"\u0127\7C\2\2\u0127\u0128\7V\2\2\u0128\u0129\7C\2\2\u0129\u012a\7N\2\2"+
|
||||
"\u012a\u012b\7Q\2\2\u012b\u012c\7I\2\2\u012c\u012d\7U\2\2\u012d\"\3\2"+
|
||||
"\2\2\u012e\u012f\7E\2\2\u012f\u0130\7Q\2\2\u0130\u0131\7N\2\2\u0131\u0132"+
|
||||
"\7W\2\2\u0132\u0133\7O\2\2\u0133\u0134\7P\2\2\u0134\u0135\7U\2\2\u0135"+
|
||||
"$\3\2\2\2\u0136\u0137\7F\2\2\u0137\u0138\7G\2\2\u0138\u0139\7D\2\2\u0139"+
|
||||
"\u013a\7W\2\2\u013a\u013b\7I\2\2\u013b&\3\2\2\2\u013c\u013d\7F\2\2\u013d"+
|
||||
"\u013e\7G\2\2\u013e\u013f\7U\2\2\u013f\u0140\7E\2\2\u0140(\3\2\2\2\u0141"+
|
||||
"\u0142\7F\2\2\u0142\u0143\7G\2\2\u0143\u0144\7U\2\2\u0144\u0145\7E\2\2"+
|
||||
"\u0145\u0146\7T\2\2\u0146\u0147\7K\2\2\u0147\u0148\7D\2\2\u0148\u0149"+
|
||||
"\7G\2\2\u0149*\3\2\2\2\u014a\u014b\7F\2\2\u014b\u014c\7K\2\2\u014c\u014d"+
|
||||
"\7U\2\2\u014d\u014e\7V\2\2\u014e\u014f\7K\2\2\u014f\u0150\7P\2\2\u0150"+
|
||||
"\u0151\7E\2\2\u0151\u0152\7V\2\2\u0152,\3\2\2\2\u0153\u0154\7G\2\2\u0154"+
|
||||
"\u0155\7U\2\2\u0155\u0156\7E\2\2\u0156\u0157\7C\2\2\u0157\u0158\7R\2\2"+
|
||||
"\u0158\u0159\7G\2\2\u0159.\3\2\2\2\u015a\u015b\7G\2\2\u015b\u015c\7Z\2"+
|
||||
"\2\u015c\u015d\7G\2\2\u015d\u015e\7E\2\2\u015e\u015f\7W\2\2\u015f\u0160"+
|
||||
"\7V\2\2\u0160\u0161\7C\2\2\u0161\u0162\7D\2\2\u0162\u0163\7N\2\2\u0163"+
|
||||
"\u0164\7G\2\2\u0164\60\3\2\2\2\u0165\u0166\7G\2\2\u0166\u0167\7Z\2\2\u0167"+
|
||||
"\u0168\7K\2\2\u0168\u0169\7U\2\2\u0169\u016a\7V\2\2\u016a\u016b\7U\2\2"+
|
||||
"\u016b\62\3\2\2\2\u016c\u016d\7G\2\2\u016d\u016e\7Z\2\2\u016e\u016f\7"+
|
||||
"R\2\2\u016f\u0170\7N\2\2\u0170\u0171\7C\2\2\u0171\u0172\7K\2\2\u0172\u0173"+
|
||||
"\7P\2\2\u0173\64\3\2\2\2\u0174\u0175\7G\2\2\u0175\u0176\7Z\2\2\u0176\u0177"+
|
||||
"\7V\2\2\u0177\u0178\7T\2\2\u0178\u0179\7C\2\2\u0179\u017a\7E\2\2\u017a"+
|
||||
"\u017b\7V\2\2\u017b\66\3\2\2\2\u017c\u017d\7H\2\2\u017d\u017e\7C\2\2\u017e"+
|
||||
"\u017f\7N\2\2\u017f\u0180\7U\2\2\u0180\u0181\7G\2\2\u01818\3\2\2\2\u0182"+
|
||||
"\u0183\7H\2\2\u0183\u0184\7K\2\2\u0184\u0185\7T\2\2\u0185\u0186\7U\2\2"+
|
||||
"\u0186\u0187\7V\2\2\u0187:\3\2\2\2\u0188\u0189\7H\2\2\u0189\u018a\7Q\2"+
|
||||
"\2\u018a\u018b\7T\2\2\u018b\u018c\7O\2\2\u018c\u018d\7C\2\2\u018d\u018e"+
|
||||
"\7V\2\2\u018e<\3\2\2\2\u018f\u0190\7H\2\2\u0190\u0191\7T\2\2\u0191\u0192"+
|
||||
"\7Q\2\2\u0192\u0193\7O\2\2\u0193>\3\2\2\2\u0194\u0195\7H\2\2\u0195\u0196"+
|
||||
"\7W\2\2\u0196\u0197\7N\2\2\u0197\u0198\7N\2\2\u0198@\3\2\2\2\u0199\u019a"+
|
||||
"\7H\2\2\u019a\u019b\7W\2\2\u019b\u019c\7P\2\2\u019c\u019d\7E\2\2\u019d"+
|
||||
"\u019e\7V\2\2\u019e\u019f\7K\2\2\u019f\u01a0\7Q\2\2\u01a0\u01a1\7P\2\2"+
|
||||
"\u01a1\u01a2\7U\2\2\u01a2B\3\2\2\2\u01a3\u01a4\7I\2\2\u01a4\u01a5\7T\2"+
|
||||
"\2\u01a5\u01a6\7C\2\2\u01a6\u01a7\7R\2\2\u01a7\u01a8\7J\2\2\u01a8\u01a9"+
|
||||
"\7X\2\2\u01a9\u01aa\7K\2\2\u01aa\u01ab\7\\\2\2\u01abD\3\2\2\2\u01ac\u01ad"+
|
||||
"\7I\2\2\u01ad\u01ae\7T\2\2\u01ae\u01af\7Q\2\2\u01af\u01b0\7W\2\2\u01b0"+
|
||||
"\u01b1\7R\2\2\u01b1F\3\2\2\2\u01b2\u01b3\7J\2\2\u01b3\u01b4\7C\2\2\u01b4"+
|
||||
"\u01b5\7X\2\2\u01b5\u01b6\7K\2\2\u01b6\u01b7\7P\2\2\u01b7\u01b8\7I\2\2"+
|
||||
"\u01b8H\3\2\2\2\u01b9\u01ba\7K\2\2\u01ba\u01bb\7P\2\2\u01bbJ\3\2\2\2\u01bc"+
|
||||
"\u01bd\7K\2\2\u01bd\u01be\7P\2\2\u01be\u01bf\7P\2\2\u01bf\u01c0\7G\2\2"+
|
||||
"\u01c0\u01c1\7T\2\2\u01c1L\3\2\2\2\u01c2\u01c3\7K\2\2\u01c3\u01c4\7U\2"+
|
||||
"\2\u01c4N\3\2\2\2\u01c5\u01c6\7L\2\2\u01c6\u01c7\7Q\2\2\u01c7\u01c8\7"+
|
||||
"K\2\2\u01c8\u01c9\7P\2\2\u01c9P\3\2\2\2\u01ca\u01cb\7N\2\2\u01cb\u01cc"+
|
||||
"\7C\2\2\u01cc\u01cd\7U\2\2\u01cd\u01ce\7V\2\2\u01ceR\3\2\2\2\u01cf\u01d0"+
|
||||
"\7N\2\2\u01d0\u01d1\7G\2\2\u01d1\u01d2\7H\2\2\u01d2\u01d3\7V\2\2\u01d3"+
|
||||
"T\3\2\2\2\u01d4\u01d5\7N\2\2\u01d5\u01d6\7K\2\2\u01d6\u01d7\7M\2\2\u01d7"+
|
||||
"\u01d8\7G\2\2\u01d8V\3\2\2\2\u01d9\u01da\7N\2\2\u01da\u01db\7K\2\2\u01db"+
|
||||
"\u01dc\7O\2\2\u01dc\u01dd\7K\2\2\u01dd\u01de\7V\2\2\u01deX\3\2\2\2\u01df"+
|
||||
"\u01e0\7O\2\2\u01e0\u01e1\7C\2\2\u01e1\u01e2\7R\2\2\u01e2\u01e3\7R\2\2"+
|
||||
"\u01e3\u01e4\7G\2\2\u01e4\u01e5\7F\2\2\u01e5Z\3\2\2\2\u01e6\u01e7\7O\2"+
|
||||
"\2\u01e7\u01e8\7C\2\2\u01e8\u01e9\7V\2\2\u01e9\u01ea\7E\2\2\u01ea\u01eb"+
|
||||
"\7J\2\2\u01eb\\\3\2\2\2\u01ec\u01ed\7P\2\2\u01ed\u01ee\7C\2\2\u01ee\u01ef"+
|
||||
"\7V\2\2\u01ef\u01f0\7W\2\2\u01f0\u01f1\7T\2\2\u01f1\u01f2\7C\2\2\u01f2"+
|
||||
"\u01f3\7N\2\2\u01f3^\3\2\2\2\u01f4\u01f5\7P\2\2\u01f5\u01f6\7Q\2\2\u01f6"+
|
||||
"\u01f7\7V\2\2\u01f7`\3\2\2\2\u01f8\u01f9\7P\2\2\u01f9\u01fa\7W\2\2\u01fa"+
|
||||
"\u01fb\7N\2\2\u01fb\u01fc\7N\2\2\u01fcb\3\2\2\2\u01fd\u01fe\7P\2\2\u01fe"+
|
||||
"\u01ff\7W\2\2\u01ff\u0200\7N\2\2\u0200\u0201\7N\2\2\u0201\u0202\7U\2\2"+
|
||||
"\u0202d\3\2\2\2\u0203\u0204\7Q\2\2\u0204\u0205\7P\2\2\u0205f\3\2\2\2\u0206"+
|
||||
"\u0207\7Q\2\2\u0207\u0208\7R\2\2\u0208\u0209\7V\2\2\u0209\u020a\7K\2\2"+
|
||||
"\u020a\u020b\7O\2\2\u020b\u020c\7K\2\2\u020c\u020d\7\\\2\2\u020d\u020e"+
|
||||
"\7G\2\2\u020e\u020f\7F\2\2\u020fh\3\2\2\2\u0210\u0211\7Q\2\2\u0211\u0212"+
|
||||
"\7T\2\2\u0212j\3\2\2\2\u0213\u0214\7Q\2\2\u0214\u0215\7T\2\2\u0215\u0216"+
|
||||
"\7F\2\2\u0216\u0217\7G\2\2\u0217\u0218\7T\2\2\u0218l\3\2\2\2\u0219\u021a"+
|
||||
"\7Q\2\2\u021a\u021b\7W\2\2\u021b\u021c\7V\2\2\u021c\u021d\7G\2\2\u021d"+
|
||||
"\u021e\7T\2\2\u021en\3\2\2\2\u021f\u0220\7R\2\2\u0220\u0221\7C\2\2\u0221"+
|
||||
"\u0222\7T\2\2\u0222\u0223\7U\2\2\u0223\u0224\7G\2\2\u0224\u0225\7F\2\2"+
|
||||
"\u0225p\3\2\2\2\u0226\u0227\7R\2\2\u0227\u0228\7J\2\2\u0228\u0229\7[\2"+
|
||||
"\2\u0229\u022a\7U\2\2\u022a\u022b\7K\2\2\u022b\u022c\7E\2\2\u022c\u022d"+
|
||||
"\7C\2\2\u022d\u022e\7N\2\2\u022er\3\2\2\2\u022f\u0230\7R\2\2\u0230\u0231"+
|
||||
"\7N\2\2\u0231\u0232\7C\2\2\u0232\u0233\7P\2\2\u0233t\3\2\2\2\u0234\u0235"+
|
||||
"\7T\2\2\u0235\u0236\7K\2\2\u0236\u0237\7I\2\2\u0237\u0238\7J\2\2\u0238"+
|
||||
"\u0239\7V\2\2\u0239v\3\2\2\2\u023a\u023b\7T\2\2\u023b\u023c\7N\2\2\u023c"+
|
||||
"\u023d\7K\2\2\u023d\u023e\7M\2\2\u023e\u023f\7G\2\2\u023fx\3\2\2\2\u0240"+
|
||||
"\u0241\7S\2\2\u0241\u0242\7W\2\2\u0242\u0243\7G\2\2\u0243\u0244\7T\2\2"+
|
||||
"\u0244\u0245\7[\2\2\u0245z\3\2\2\2\u0246\u0247\7U\2\2\u0247\u0248\7E\2"+
|
||||
"\2\u0248\u0249\7J\2\2\u0249\u024a\7G\2\2\u024a\u024b\7O\2\2\u024b\u024c"+
|
||||
"\7C\2\2\u024c\u024d\7U\2\2\u024d|\3\2\2\2\u024e\u024f\7U\2\2\u024f\u0250"+
|
||||
"\7G\2\2\u0250\u0251\7N\2\2\u0251\u0252\7G\2\2\u0252\u0253\7E\2\2\u0253"+
|
||||
"\u0254\7V\2\2\u0254~\3\2\2\2\u0255\u0256\7U\2\2\u0256\u0257\7J\2\2\u0257"+
|
||||
"\u0258\7Q\2\2\u0258\u0259\7Y\2\2\u0259\u0080\3\2\2\2\u025a\u025b\7U\2"+
|
||||
"\2\u025b\u025c\7[\2\2\u025c\u025d\7U\2\2\u025d\u0082\3\2\2\2\u025e\u025f"+
|
||||
"\7V\2\2\u025f\u0260\7C\2\2\u0260\u0261\7D\2\2\u0261\u0262\7N\2\2\u0262"+
|
||||
"\u0263\7G\2\2\u0263\u0084\3\2\2\2\u0264\u0265\7V\2\2\u0265\u0266\7C\2"+
|
||||
"\2\u0266\u0267\7D\2\2\u0267\u0268\7N\2\2\u0268\u0269\7G\2\2\u0269\u026a"+
|
||||
"\7U\2\2\u026a\u0086\3\2\2\2\u026b\u026c\7V\2\2\u026c\u026d\7G\2\2\u026d"+
|
||||
"\u026e\7Z\2\2\u026e\u026f\7V\2\2\u026f\u0088\3\2\2\2\u0270\u0271\7V\2"+
|
||||
"\2\u0271\u0272\7T\2\2\u0272\u0273\7W\2\2\u0273\u0274\7G\2\2\u0274\u008a"+
|
||||
"\3\2\2\2\u0275\u0276\7V\2\2\u0276\u0277\7[\2\2\u0277\u0278\7R\2\2\u0278"+
|
||||
"\u0279\7G\2\2\u0279\u008c\3\2\2\2\u027a\u027b\7V\2\2\u027b\u027c\7[\2"+
|
||||
"\2\u027c\u027d\7R\2\2\u027d\u027e\7G\2\2\u027e\u027f\7U\2\2\u027f\u008e"+
|
||||
"\3\2\2\2\u0280\u0281\7W\2\2\u0281\u0282\7U\2\2\u0282\u0283\7K\2\2\u0283"+
|
||||
"\u0284\7P\2\2\u0284\u0285\7I\2\2\u0285\u0090\3\2\2\2\u0286\u0287\7X\2"+
|
||||
"\2\u0287\u0288\7G\2\2\u0288\u0289\7T\2\2\u0289\u028a\7K\2\2\u028a\u028b"+
|
||||
"\7H\2\2\u028b\u028c\7[\2\2\u028c\u0092\3\2\2\2\u028d\u028e\7Y\2\2\u028e"+
|
||||
"\u028f\7J\2\2\u028f\u0290\7G\2\2\u0290\u0291\7T\2\2\u0291\u0292\7G\2\2"+
|
||||
"\u0292\u0094\3\2\2\2\u0293\u0294\7Y\2\2\u0294\u0295\7K\2\2\u0295\u0296"+
|
||||
"\7V\2\2\u0296\u0297\7J\2\2\u0297\u0096\3\2\2\2\u0298\u0299\7}\2\2\u0299"+
|
||||
"\u029a\7G\2\2\u029a\u029b\7U\2\2\u029b\u029c\7E\2\2\u029c\u029d\7C\2\2"+
|
||||
"\u029d\u029e\7R\2\2\u029e\u029f\7G\2\2\u029f\u0098\3\2\2\2\u02a0\u02a1"+
|
||||
"\7}\2\2\u02a1\u02a2\7H\2\2\u02a2\u02a3\7P\2\2\u02a3\u009a\3\2\2\2\u02a4"+
|
||||
"\u02a5\7}\2\2\u02a5\u02a6\7N\2\2\u02a6\u02a7\7K\2\2\u02a7\u02a8\7O\2\2"+
|
||||
"\u02a8\u02a9\7K\2\2\u02a9\u02aa\7V\2\2\u02aa\u009c\3\2\2\2\u02ab\u02ac"+
|
||||
"\7}\2\2\u02ac\u02ad\7F\2\2\u02ad\u009e\3\2\2\2\u02ae\u02af\7}\2\2\u02af"+
|
||||
"\u02b0\7V\2\2\u02b0\u00a0\3\2\2\2\u02b1\u02b2\7}\2\2\u02b2\u02b3\7V\2"+
|
||||
"\2\u02b3\u02b4\7U\2\2\u02b4\u00a2\3\2\2\2\u02b5\u02b6\7}\2\2\u02b6\u02b7"+
|
||||
"\7I\2\2\u02b7\u02b8\7W\2\2\u02b8\u02b9\7K\2\2\u02b9\u02ba\7F\2\2\u02ba"+
|
||||
"\u00a4\3\2\2\2\u02bb\u02bc\7\177\2\2\u02bc\u00a6\3\2\2\2\u02bd\u02be\7"+
|
||||
"?\2\2\u02be\u00a8\3\2\2\2\u02bf\u02c0\7>\2\2\u02c0\u02c7\7@\2\2\u02c1"+
|
||||
"\u02c2\7#\2\2\u02c2\u02c7\7?\2\2\u02c3\u02c4\7>\2\2\u02c4\u02c5\7?\2\2"+
|
||||
"\u02c5\u02c7\7@\2\2\u02c6\u02bf\3\2\2\2\u02c6\u02c1\3\2\2\2\u02c6\u02c3"+
|
||||
"\3\2\2\2\u02c7\u00aa\3\2\2\2\u02c8\u02c9\7>\2\2\u02c9\u00ac\3\2\2\2\u02ca"+
|
||||
"\u02cb\7>\2\2\u02cb\u02cc\7?\2\2\u02cc\u00ae\3\2\2\2\u02cd\u02ce\7@\2"+
|
||||
"\2\u02ce\u00b0\3\2\2\2\u02cf\u02d0\7@\2\2\u02d0\u02d1\7?\2\2\u02d1\u00b2"+
|
||||
"\3\2\2\2\u02d2\u02d3\7-\2\2\u02d3\u00b4\3\2\2\2\u02d4\u02d5\7/\2\2\u02d5"+
|
||||
"\u00b6\3\2\2\2\u02d6\u02d7\7,\2\2\u02d7\u00b8\3\2\2\2\u02d8\u02d9\7\61"+
|
||||
"\2\2\u02d9\u00ba\3\2\2\2\u02da\u02db\7\'\2\2\u02db\u00bc\3\2\2\2\u02dc"+
|
||||
"\u02dd\7~\2\2\u02dd\u02de\7~\2\2\u02de\u00be\3\2\2\2\u02df\u02e0\7\60"+
|
||||
"\2\2\u02e0\u00c0\3\2\2\2\u02e1\u02e2\7A\2\2\u02e2\u00c2\3\2\2\2\u02e3"+
|
||||
"\u02e9\7)\2\2\u02e4\u02e8\n\2\2\2\u02e5\u02e6\7)\2\2\u02e6\u02e8\7)\2"+
|
||||
"\2\u02e7\u02e4\3\2\2\2\u02e7\u02e5\3\2\2\2\u02e8\u02eb\3\2\2\2\u02e9\u02e7"+
|
||||
"\3\2\2\2\u02e9\u02ea\3\2\2\2\u02ea\u02ec\3\2\2\2\u02eb\u02e9\3\2\2\2\u02ec"+
|
||||
"\u02ed\7)\2\2\u02ed\u00c4\3\2\2\2\u02ee\u02f0\5\u00d5k\2\u02ef\u02ee\3"+
|
||||
"\2\2\2\u02f0\u02f1\3\2\2\2\u02f1\u02ef\3\2\2\2\u02f1\u02f2\3\2\2\2\u02f2"+
|
||||
"\u00c6\3\2\2\2\u02f3\u02f5\5\u00d5k\2\u02f4\u02f3\3\2\2\2\u02f5\u02f6"+
|
||||
"\3\2\2\2\u02f6\u02f4\3\2\2\2\u02f6\u02f7\3\2\2\2\u02f7\u02f8\3\2\2\2\u02f8"+
|
||||
"\u02fc\5\u00bf`\2\u02f9\u02fb\5\u00d5k\2\u02fa\u02f9\3\2\2\2\u02fb\u02fe"+
|
||||
"\3\2\2\2\u02fc\u02fa\3\2\2\2\u02fc\u02fd\3\2\2\2\u02fd\u031e\3\2\2\2\u02fe"+
|
||||
"\u02fc\3\2\2\2\u02ff\u0301\5\u00bf`\2\u0300\u0302\5\u00d5k\2\u0301\u0300"+
|
||||
"\3\2\2\2\u0302\u0303\3\2\2\2\u0303\u0301\3\2\2\2\u0303\u0304\3\2\2\2\u0304"+
|
||||
"\u031e\3\2\2\2\u0305\u0307\5\u00d5k\2\u0306\u0305\3\2\2\2\u0307\u0308"+
|
||||
"\3\2\2\2\u0308\u0306\3\2\2\2\u0308\u0309\3\2\2\2\u0309\u0311\3\2\2\2\u030a"+
|
||||
"\u030e\5\u00bf`\2\u030b\u030d\5\u00d5k\2\u030c\u030b\3\2\2\2\u030d\u0310"+
|
||||
"\3\2\2\2\u030e\u030c\3\2\2\2\u030e\u030f\3\2\2\2\u030f\u0312\3\2\2\2\u0310"+
|
||||
"\u030e\3\2\2\2\u0311\u030a\3\2\2\2\u0311\u0312\3\2\2\2\u0312\u0313\3\2"+
|
||||
"\2\2\u0313\u0314\5\u00d3j\2\u0314\u031e\3\2\2\2\u0315\u0317\5\u00bf`\2"+
|
||||
"\u0316\u0318\5\u00d5k\2\u0317\u0316\3\2\2\2\u0318\u0319\3\2\2\2\u0319"+
|
||||
"\u0317\3\2\2\2\u0319\u031a\3\2\2\2\u031a\u031b\3\2\2\2\u031b\u031c\5\u00d3"+
|
||||
"j\2\u031c\u031e\3\2\2\2\u031d\u02f4\3\2\2\2\u031d\u02ff\3\2\2\2\u031d"+
|
||||
"\u0306\3\2\2\2\u031d\u0315\3\2\2\2\u031e\u00c8\3\2\2\2\u031f\u0322\5\u00d7"+
|
||||
"l\2\u0320\u0322\7a\2\2\u0321\u031f\3\2\2\2\u0321\u0320\3\2\2\2\u0322\u0328"+
|
||||
"\3\2\2\2\u0323\u0327\5\u00d7l\2\u0324\u0327\5\u00d5k\2\u0325\u0327\t\3"+
|
||||
"\2\2\u0326\u0323\3\2\2\2\u0326\u0324\3\2\2\2\u0326\u0325\3\2\2\2\u0327"+
|
||||
"\u032a\3\2\2\2\u0328\u0326\3\2\2\2\u0328\u0329\3\2\2\2\u0329\u00ca\3\2"+
|
||||
"\2\2\u032a\u0328\3\2\2\2\u032b\u032f\5\u00d5k\2\u032c\u0330\5\u00d7l\2"+
|
||||
"\u032d\u0330\5\u00d5k\2\u032e\u0330\t\4\2\2\u032f\u032c\3\2\2\2\u032f"+
|
||||
"\u032d\3\2\2\2\u032f\u032e\3\2\2\2\u0330\u0331\3\2\2\2\u0331\u032f\3\2"+
|
||||
"\2\2\u0331\u0332\3\2\2\2\u0332\u00cc\3\2\2\2\u0333\u0337\5\u00d7l\2\u0334"+
|
||||
"\u0337\5\u00d5k\2\u0335\u0337\7a\2\2\u0336\u0333\3\2\2\2\u0336\u0334\3"+
|
||||
"\2\2\2\u0336\u0335\3\2\2\2\u0337\u0338\3\2\2\2\u0338\u0336\3\2\2\2\u0338"+
|
||||
"\u0339\3\2\2\2\u0339\u00ce\3\2\2\2\u033a\u0340\7$\2\2\u033b\u033f\n\5"+
|
||||
"\2\2\u033c\u033d\7$\2\2\u033d\u033f\7$\2\2\u033e\u033b\3\2\2\2\u033e\u033c"+
|
||||
"\3\2\2\2\u033f\u0342\3\2\2\2\u0340\u033e\3\2\2\2\u0340\u0341\3\2\2\2\u0341"+
|
||||
"\u0343\3\2\2\2\u0342\u0340\3\2\2\2\u0343\u0344\7$\2\2\u0344\u00d0\3\2"+
|
||||
"\2\2\u0345\u034b\7b\2\2\u0346\u034a\n\6\2\2\u0347\u0348\7b\2\2\u0348\u034a"+
|
||||
"\7b\2\2\u0349\u0346\3\2\2\2\u0349\u0347\3\2\2\2\u034a\u034d\3\2\2\2\u034b"+
|
||||
"\u0349\3\2\2\2\u034b\u034c\3\2\2\2\u034c\u034e\3\2\2\2\u034d\u034b\3\2"+
|
||||
"\2\2\u034e\u034f\7b\2\2\u034f\u00d2\3\2\2\2\u0350\u0352\7G\2\2\u0351\u0353"+
|
||||
"\t\7\2\2\u0352\u0351\3\2\2\2\u0352\u0353\3\2\2\2\u0353\u0355\3\2\2\2\u0354"+
|
||||
"\u0356\5\u00d5k\2\u0355\u0354\3\2\2\2\u0356\u0357\3\2\2\2\u0357\u0355"+
|
||||
"\3\2\2\2\u0357\u0358\3\2\2\2\u0358\u00d4\3\2\2\2\u0359\u035a\t\b\2\2\u035a"+
|
||||
"\u00d6\3\2\2\2\u035b\u035c\t\t\2\2\u035c\u00d8\3\2\2\2\u035d\u035e\7/"+
|
||||
"\2\2\u035e\u035f\7/\2\2\u035f\u0363\3\2\2\2\u0360\u0362\n\n\2\2\u0361"+
|
||||
"\u0360\3\2\2\2\u0362\u0365\3\2\2\2\u0363\u0361\3\2\2\2\u0363\u0364\3\2"+
|
||||
"\2\2\u0364\u0367\3\2\2\2\u0365\u0363\3\2\2\2\u0366\u0368\7\17\2\2\u0367"+
|
||||
"\u0366\3\2\2\2\u0367\u0368\3\2\2\2\u0368\u036a\3\2\2\2\u0369\u036b\7\f"+
|
||||
"\2\2\u036a\u0369\3\2\2\2\u036a\u036b\3\2\2\2\u036b\u036c\3\2\2\2\u036c"+
|
||||
"\u036d\bm\2\2\u036d\u00da\3\2\2\2\u036e\u036f\7\61\2\2\u036f\u0370\7,"+
|
||||
"\2\2\u0370\u0375\3\2\2\2\u0371\u0374\5\u00dbn\2\u0372\u0374\13\2\2\2\u0373"+
|
||||
"\u0371\3\2\2\2\u0373\u0372\3\2\2\2\u0374\u0377\3\2\2\2\u0375\u0376\3\2"+
|
||||
"\2\2\u0375\u0373\3\2\2\2\u0376\u0378\3\2\2\2\u0377\u0375\3\2\2\2\u0378"+
|
||||
"\u0379\7,\2\2\u0379\u037a\7\61\2\2\u037a\u037b\3\2\2\2\u037b\u037c\bn"+
|
||||
"\2\2\u037c\u00dc\3\2\2\2\u037d\u037f\t\13\2\2\u037e\u037d\3\2\2\2\u037f"+
|
||||
"\u0380\3\2\2\2\u0380\u037e\3\2\2\2\u0380\u0381\3\2\2\2\u0381\u0382\3\2"+
|
||||
"\2\2\u0382\u0383\bo\2\2\u0383\u00de\3\2\2\2\u0384\u0385\13\2\2\2\u0385"+
|
||||
"\u00e0\3\2\2\2\"\2\u02c6\u02e7\u02e9\u02f1\u02f6\u02fc\u0303\u0308\u030e"+
|
||||
"\u0311\u0319\u031d\u0321\u0326\u0328\u032f\u0331\u0336\u0338\u033e\u0340"+
|
||||
"\u0349\u034b\u0352\u0357\u0363\u0367\u036a\u0373\u0375\u0380\3\2\3\2";
|
||||
public static final ATN _ATN =
|
||||
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
|
||||
static {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -53,6 +53,7 @@ import org.elasticsearch.xpack.sql.querydsl.container.QueryContainer;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.ScoreSort;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.ScriptSort;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.Sort.Direction;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.Sort.Missing;
|
||||
import org.elasticsearch.xpack.sql.querydsl.query.Query;
|
||||
import org.elasticsearch.xpack.sql.rule.Rule;
|
||||
import org.elasticsearch.xpack.sql.rule.RuleExecutor;
|
||||
@ -423,6 +424,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
||||
|
||||
for (Order order : plan.order()) {
|
||||
Direction direction = Direction.from(order.direction());
|
||||
Missing missing = Missing.from(order.nullsPosition());
|
||||
|
||||
// check whether sorting is on an group (and thus nested agg) or field
|
||||
Attribute attr = ((NamedExpression) order.child()).toAttribute();
|
||||
@ -451,19 +453,19 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
||||
if (sfa.orderBy() instanceof NamedExpression) {
|
||||
Attribute at = ((NamedExpression) sfa.orderBy()).toAttribute();
|
||||
at = qContainer.aliases().getOrDefault(at, at);
|
||||
qContainer = qContainer.sort(new AttributeSort(at, direction));
|
||||
qContainer = qContainer.sort(new AttributeSort(at, direction, missing));
|
||||
} else if (!sfa.orderBy().foldable()) {
|
||||
// ignore constant
|
||||
throw new PlanningException("does not know how to order by expression {}", sfa.orderBy());
|
||||
}
|
||||
} else {
|
||||
// nope, use scripted sorting
|
||||
qContainer = qContainer.sort(new ScriptSort(sfa.script(), direction));
|
||||
qContainer = qContainer.sort(new ScriptSort(sfa.script(), direction, missing));
|
||||
}
|
||||
} else if (attr instanceof ScoreAttribute) {
|
||||
qContainer = qContainer.sort(new ScoreSort(direction));
|
||||
qContainer = qContainer.sort(new ScoreSort(direction, missing));
|
||||
} else {
|
||||
qContainer = qContainer.sort(new AttributeSort(attr, direction));
|
||||
qContainer = qContainer.sort(new AttributeSort(attr, direction, missing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,15 +32,14 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeHistogramFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.IsNotNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Or;
|
||||
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.MultiMatchQueryPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.StringQueryPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Or;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparison;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThan;
|
||||
@ -50,6 +49,7 @@ import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Less
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.regex.Like;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.regex.LikePattern;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.regex.RLike;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.regex.RegexMatch;
|
||||
import org.elasticsearch.xpack.sql.querydsl.agg.AggFilter;
|
||||
import org.elasticsearch.xpack.sql.querydsl.agg.AndAggFilter;
|
||||
import org.elasticsearch.xpack.sql.querydsl.agg.AvgAgg;
|
||||
@ -394,10 +394,10 @@ abstract class QueryTranslator {
|
||||
|
||||
// TODO: need to optimize on ngram
|
||||
// TODO: see whether escaping is needed
|
||||
static class Likes extends ExpressionTranslator<BinaryPredicate> {
|
||||
static class Likes extends ExpressionTranslator<RegexMatch> {
|
||||
|
||||
@Override
|
||||
protected QueryTranslation asQuery(BinaryPredicate e, boolean onAggs) {
|
||||
protected QueryTranslation asQuery(RegexMatch e, boolean onAggs) {
|
||||
Query q = null;
|
||||
boolean inexact = true;
|
||||
String target = null;
|
||||
@ -412,7 +412,7 @@ abstract class QueryTranslator {
|
||||
}
|
||||
|
||||
if (e instanceof Like) {
|
||||
LikePattern p = ((Like) e).right();
|
||||
LikePattern p = ((Like) e).pattern();
|
||||
if (inexact) {
|
||||
q = new QueryStringQuery(e.location(), p.asLuceneWildcard(), target);
|
||||
}
|
||||
@ -459,10 +459,10 @@ abstract class QueryTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
static class BinaryLogic extends ExpressionTranslator<BinaryPredicate> {
|
||||
static class BinaryLogic extends ExpressionTranslator<org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogic> {
|
||||
|
||||
@Override
|
||||
protected QueryTranslation asQuery(BinaryPredicate e, boolean onAggs) {
|
||||
protected QueryTranslation asQuery(org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogic e, boolean onAggs) {
|
||||
if (e instanceof And) {
|
||||
return and(e.location(), toQuery(e.left(), onAggs), toQuery(e.right(), onAggs));
|
||||
}
|
||||
|
@ -5,20 +5,20 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.querydsl.agg;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.search.aggregations.PipelineAggregationBuilder;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.util.Check;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.search.aggregations.pipeline.PipelineAggregatorBuilders.bucketSelector;
|
||||
|
||||
public class AggFilter extends PipelineAgg {
|
||||
|
||||
private static final String BUCKET_SELECTOR_ID_PREFIX = "having";
|
||||
private static final String BUCKET_SELECTOR_ID_PREFIX = "having.";
|
||||
|
||||
private final ScriptTemplate scriptTemplate;
|
||||
private final Map<String, String> aggPaths;
|
||||
|
@ -5,14 +5,7 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.querydsl.agg;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Params;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
|
||||
|
||||
public class AndAggFilter extends AggFilter {
|
||||
|
||||
@ -21,12 +14,6 @@ public class AndAggFilter extends AggFilter {
|
||||
}
|
||||
|
||||
public AndAggFilter(String name, AggFilter left, AggFilter right) {
|
||||
super(name, and(left.scriptTemplate(), right.scriptTemplate()));
|
||||
}
|
||||
|
||||
private static ScriptTemplate and(ScriptTemplate left, ScriptTemplate right) {
|
||||
String template = format(Locale.ROOT, "( %s ) && ( %s )", left.template(), right.template());
|
||||
Params params = new ParamsBuilder().script(left.params()).script(right.params()).build();
|
||||
return new ScriptTemplate(template, params, DataType.BOOLEAN);
|
||||
super(name, Scripts.and(left.scriptTemplate(), right.scriptTemplate()));
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,7 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.querydsl.agg;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Params;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
|
||||
|
||||
public class OrAggFilter extends AggFilter {
|
||||
|
||||
@ -21,12 +14,6 @@ public class OrAggFilter extends AggFilter {
|
||||
}
|
||||
|
||||
public OrAggFilter(String name, AggFilter left, AggFilter right) {
|
||||
super(name, and(left.scriptTemplate(), right.scriptTemplate()));
|
||||
}
|
||||
|
||||
private static ScriptTemplate and(ScriptTemplate left, ScriptTemplate right) {
|
||||
String template = format(Locale.ROOT, "( %s ) || ( %s )", left.template(), right.template());
|
||||
Params params = new ParamsBuilder().script(left.params()).script(right.params()).build();
|
||||
return new ScriptTemplate(template, params, DataType.BOOLEAN);
|
||||
super(name, Scripts.or(left.scriptTemplate(), right.scriptTemplate()));
|
||||
}
|
||||
}
|
||||
|
@ -5,16 +5,16 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.querydsl.container;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Attribute;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AttributeSort extends Sort {
|
||||
|
||||
private final Attribute attribute;
|
||||
|
||||
public AttributeSort(Attribute attribute, Direction direction) {
|
||||
super(direction);
|
||||
public AttributeSort(Attribute attribute, Direction direction, Missing missing) {
|
||||
super(direction, missing);
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ public class AttributeSort extends Sort {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(attribute, direction());
|
||||
return Objects.hash(attribute, direction(), missing());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -39,6 +39,7 @@ public class AttributeSort extends Sort {
|
||||
|
||||
AttributeSort other = (AttributeSort) obj;
|
||||
return Objects.equals(direction(), other.direction())
|
||||
&& Objects.equals(missing(), other.missing())
|
||||
&& Objects.equals(attribute, other.attribute);
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ package org.elasticsearch.xpack.sql.querydsl.container;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ScoreSort extends Sort {
|
||||
public ScoreSort(Direction direction) {
|
||||
super(direction);
|
||||
public ScoreSort(Direction direction, Missing missing) {
|
||||
super(direction, missing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(direction());
|
||||
return Objects.hash(direction(), missing());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -28,6 +28,7 @@ public class ScoreSort extends Sort {
|
||||
}
|
||||
|
||||
ScriptSort other = (ScriptSort) obj;
|
||||
return Objects.equals(direction(), other.direction());
|
||||
return Objects.equals(direction(), other.direction())
|
||||
&& Objects.equals(missing(), other.missing());
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package org.elasticsearch.xpack.sql.querydsl.container;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -13,9 +14,9 @@ public class ScriptSort extends Sort {
|
||||
|
||||
private final ScriptTemplate script;
|
||||
|
||||
public ScriptSort(ScriptTemplate script, Direction direction) {
|
||||
super(direction);
|
||||
this.script = script;
|
||||
public ScriptSort(ScriptTemplate script, Direction direction, Missing missing) {
|
||||
super(direction, missing);
|
||||
this.script = Scripts.nullSafeSort(script);
|
||||
}
|
||||
|
||||
public ScriptTemplate script() {
|
||||
@ -24,7 +25,7 @@ public class ScriptSort extends Sort {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(direction(), script);
|
||||
return Objects.hash(direction(), missing(), script);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -39,6 +40,7 @@ public class ScriptSort extends Sort {
|
||||
|
||||
ScriptSort other = (ScriptSort) obj;
|
||||
return Objects.equals(direction(), other.direction())
|
||||
&& Objects.equals(missing(), other.missing())
|
||||
&& Objects.equals(script, other.script);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package org.elasticsearch.xpack.sql.querydsl.container;
|
||||
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.xpack.sql.expression.Order.NullsPosition;
|
||||
import org.elasticsearch.xpack.sql.expression.Order.OrderDirection;
|
||||
|
||||
public class Sort {
|
||||
@ -22,13 +23,37 @@ public class Sort {
|
||||
}
|
||||
}
|
||||
|
||||
private final Direction direction;
|
||||
public enum Missing {
|
||||
FIRST("_first"), LAST("_last");
|
||||
|
||||
protected Sort(Direction direction) {
|
||||
private final String position;
|
||||
|
||||
Missing(String position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public static Missing from(NullsPosition pos) {
|
||||
return pos == null || pos == NullsPosition.FIRST ? FIRST : LAST;
|
||||
}
|
||||
|
||||
public String position() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
private final Direction direction;
|
||||
private final Missing missing;
|
||||
|
||||
protected Sort(Direction direction, Missing nulls) {
|
||||
this.direction = direction;
|
||||
this.missing = nulls;
|
||||
}
|
||||
|
||||
public Direction direction() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public Missing missing() {
|
||||
return missing;
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,13 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.querydsl.query;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.scriptQuery;
|
||||
|
||||
public class ScriptQuery extends LeafQuery {
|
||||
@ -19,7 +20,8 @@ public class ScriptQuery extends LeafQuery {
|
||||
|
||||
public ScriptQuery(Location location, ScriptTemplate script) {
|
||||
super(location);
|
||||
this.script = script;
|
||||
// make script null safe
|
||||
this.script = Scripts.nullSafeFilter(script);
|
||||
}
|
||||
|
||||
public ScriptTemplate script() {
|
||||
|
@ -24,7 +24,17 @@ public class ReflectionUtils {
|
||||
c);
|
||||
}
|
||||
|
||||
return (Class<E>) typeArguments[0];
|
||||
Type tp = typeArguments[0];
|
||||
|
||||
if (tp instanceof Class<?>) {
|
||||
return (Class<E>) tp;
|
||||
} else if (tp instanceof ParameterizedType) {
|
||||
Type rawType = ((ParameterizedType) type).getRawType();
|
||||
if (rawType instanceof Class<?>) {
|
||||
return (Class<E>) rawType;
|
||||
}
|
||||
}
|
||||
throw new SqlIllegalArgumentException("Unexpected class structure for class {}", c);
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
|
@ -7,32 +7,101 @@
|
||||
# This file contains a whitelist for SQL specific utilities available inside SQL scripting
|
||||
|
||||
class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalSqlScriptUtils {
|
||||
|
||||
Integer dateTimeChrono(long, String, String)
|
||||
String dayName(long, String)
|
||||
String monthName(long, String)
|
||||
Integer quarter(long, String)
|
||||
|
||||
#
|
||||
# Utilities
|
||||
#
|
||||
def docValue(java.util.Map, String)
|
||||
boolean nullSafeFilter(Boolean)
|
||||
double nullSafeSortNumeric(Number)
|
||||
String nullSafeSortString(Object)
|
||||
|
||||
#
|
||||
# Comparison
|
||||
#
|
||||
Boolean eq(Object, Object)
|
||||
Boolean lt(Object, Object)
|
||||
Boolean lte(Object, Object)
|
||||
Boolean gt(Object, Object)
|
||||
Boolean gte(Object, Object)
|
||||
|
||||
#
|
||||
# Logical
|
||||
#
|
||||
Boolean and(Boolean, Boolean)
|
||||
Boolean or(Boolean, Boolean)
|
||||
|
||||
#
|
||||
# Regex
|
||||
#
|
||||
Boolean regex(String, String)
|
||||
|
||||
#
|
||||
# Math
|
||||
#
|
||||
Number add(Number, Number)
|
||||
Number div(Number, Number)
|
||||
Number mod(Number, Number)
|
||||
Number mul(Number, Number)
|
||||
Number sub(Number, Number)
|
||||
Number round(Number, Number)
|
||||
Number truncate(Number, Number)
|
||||
|
||||
Double abs(Number)
|
||||
Double acos(Number)
|
||||
Double asin(Number)
|
||||
Double atan(Number)
|
||||
Double cbrt(Number)
|
||||
Double ceil(Number)
|
||||
Double cos(Number)
|
||||
Double cosh(Number)
|
||||
Double cot(Number)
|
||||
Double degrees(Number)
|
||||
Double e(Number)
|
||||
Double exp(Number)
|
||||
Double expm1(Number)
|
||||
Double floor(Number)
|
||||
Double log(Number)
|
||||
Double log10(Number)
|
||||
Double pi(Number)
|
||||
Double radians(Number)
|
||||
Double random(Number)
|
||||
Double sign(Number)
|
||||
Double sin(Number)
|
||||
Double sinh(Number)
|
||||
Double sqrt(Number)
|
||||
Double tan(Number)
|
||||
|
||||
#
|
||||
# Date/Time functions
|
||||
#
|
||||
Integer dateTimeChrono(Object, String, String)
|
||||
String dayName(Object, String)
|
||||
String monthName(Object, String)
|
||||
Integer quarter(Object, String)
|
||||
|
||||
#
|
||||
# ASCII Functions
|
||||
#
|
||||
Integer ascii(String)
|
||||
Integer bitLength(String)
|
||||
String character(Number)
|
||||
String character(Number)
|
||||
Integer charLength(String)
|
||||
String concat(String, String)
|
||||
String insert(String, int, int, String)
|
||||
String lcase(String)
|
||||
String left(String, int)
|
||||
String concat(String, String)
|
||||
String insert(String, Number, Number, String)
|
||||
String lcase(String)
|
||||
String left(String, Number)
|
||||
Integer length(String)
|
||||
Integer locate(String, String)
|
||||
Integer locate(String, String, Integer)
|
||||
String ltrim(String)
|
||||
Integer locate(String, String, Number)
|
||||
String ltrim(String)
|
||||
Integer octetLength(String)
|
||||
Integer position(String, String)
|
||||
String repeat(String, int)
|
||||
String replace(String, String, String)
|
||||
String right(String, int)
|
||||
String rtrim(String)
|
||||
String space(Number)
|
||||
String substring(String, int, int)
|
||||
String ucase(String)
|
||||
String repeat(String, Number)
|
||||
String replace(String, String, String)
|
||||
String right(String, Number)
|
||||
String rtrim(String)
|
||||
String space(Number)
|
||||
String substring(String, Number, Number)
|
||||
String ucase(String)
|
||||
}
|
@ -10,6 +10,7 @@ import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
|
||||
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.sort.FieldSortBuilder;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
|
||||
@ -20,6 +21,7 @@ import org.elasticsearch.xpack.sql.querydsl.container.AttributeSort;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.QueryContainer;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.ScoreSort;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.Sort.Direction;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.Sort.Missing;
|
||||
import org.elasticsearch.xpack.sql.querydsl.query.MatchQuery;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.KeywordEsField;
|
||||
@ -84,21 +86,25 @@ public class SourceGeneratorTests extends ESTestCase {
|
||||
|
||||
public void testSortScoreSpecified() {
|
||||
QueryContainer container = new QueryContainer()
|
||||
.sort(new ScoreSort(Direction.DESC));
|
||||
.sort(new ScoreSort(Direction.DESC, null));
|
||||
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, null, randomIntBetween(1, 10));
|
||||
assertEquals(singletonList(scoreSort()), sourceBuilder.sorts());
|
||||
}
|
||||
|
||||
public void testSortFieldSpecified() {
|
||||
FieldSortBuilder sortField = fieldSort("test").unmappedType("keyword");
|
||||
|
||||
QueryContainer container = new QueryContainer()
|
||||
.sort(new AttributeSort(new FieldAttribute(new Location(1, 1), "test", new KeywordEsField("test")), Direction.ASC));
|
||||
.sort(new AttributeSort(new FieldAttribute(new Location(1, 1), "test", new KeywordEsField("test")), Direction.ASC,
|
||||
Missing.LAST));
|
||||
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, null, randomIntBetween(1, 10));
|
||||
assertEquals(singletonList(fieldSort("test").order(SortOrder.ASC)), sourceBuilder.sorts());
|
||||
assertEquals(singletonList(sortField.order(SortOrder.ASC).missing("_last")), sourceBuilder.sorts());
|
||||
|
||||
container = new QueryContainer()
|
||||
.sort(new AttributeSort(new FieldAttribute(new Location(1, 1), "test", new KeywordEsField("test")), Direction.DESC));
|
||||
.sort(new AttributeSort(new FieldAttribute(new Location(1, 1), "test", new KeywordEsField("test")), Direction.DESC,
|
||||
Missing.FIRST));
|
||||
sourceBuilder = SourceGenerator.sourceBuilder(container, null, randomIntBetween(1, 10));
|
||||
assertEquals(singletonList(fieldSort("test").order(SortOrder.DESC)), sourceBuilder.sorts());
|
||||
assertEquals(singletonList(sortField.order(SortOrder.DESC).missing("_first")), sourceBuilder.sorts());
|
||||
}
|
||||
|
||||
public void testNoSort() {
|
||||
|
@ -13,15 +13,15 @@ import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.Processors;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.ConstantProcessor;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.tree.Location.EMPTY;
|
||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.FunctionTestUtils.l;
|
||||
import static org.elasticsearch.xpack.sql.tree.Location.EMPTY;
|
||||
|
||||
public class ConcatProcessorTests extends AbstractWireSerializingTestCase<ConcatFunctionProcessor> {
|
||||
|
||||
@Override
|
||||
protected ConcatFunctionProcessor createTestInstance() {
|
||||
return new ConcatFunctionProcessor(
|
||||
new ConstantProcessor(randomRealisticUnicodeOfLengthBetween(0, 128)),
|
||||
new ConstantProcessor(randomRealisticUnicodeOfLengthBetween(0, 128)),
|
||||
new ConstantProcessor(randomRealisticUnicodeOfLengthBetween(0, 128)));
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ public class ConcatProcessorTests extends AbstractWireSerializingTestCase<Concat
|
||||
public void testConcatFunctionWithEdgeCases() {
|
||||
assertEquals("foo", new Concat(EMPTY, l("foo"), l(null)).makePipe().asProcessor().process(null));
|
||||
assertEquals("bar", new Concat(EMPTY, l(null), l("bar")).makePipe().asProcessor().process(null));
|
||||
assertNull(new Concat(EMPTY, l(null), l(null)).makePipe().asProcessor().process(null));
|
||||
assertEquals("", new Concat(EMPTY, l(null), l(null)).makePipe().asProcessor().process(null));
|
||||
}
|
||||
|
||||
public void testConcatFunctionInputsValidation() {
|
||||
|
@ -29,12 +29,12 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.math.ATan;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Abs;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.E;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Floor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.IsNotNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Or;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Range;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Or;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Add;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Div;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Mod;
|
||||
@ -204,7 +204,7 @@ public class OptimizerTests extends ESTestCase {
|
||||
// SELECT
|
||||
p = new Project(EMPTY, p, Arrays.asList(a, b));
|
||||
// ORDER BY
|
||||
p = new OrderBy(EMPTY, p, singletonList(new Order(EMPTY, b, OrderDirection.ASC)));
|
||||
p = new OrderBy(EMPTY, p, singletonList(new Order(EMPTY, b, OrderDirection.ASC, null)));
|
||||
|
||||
LogicalPlan result = new ReplaceFoldableAttributes().apply(p);
|
||||
assertNotSame(p, result);
|
||||
@ -319,7 +319,7 @@ public class OptimizerTests extends ESTestCase {
|
||||
return ((Literal) new ConstantFolding().rule(f)).value();
|
||||
}
|
||||
|
||||
private static Object foldOperator(BinaryOperator b) {
|
||||
private static Object foldOperator(BinaryOperator<?, ?, ?, ?> b) {
|
||||
return ((Literal) new ConstantFolding().rule(b)).value();
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class EscapedFunctionsTests extends ESTestCase {
|
||||
private LikePattern likeEscape(String like, String character) {
|
||||
Expression exp = parser.createExpression(format(Locale.ROOT, "exp LIKE '%s' {escape '%s'}", like, character));
|
||||
assertThat(exp, instanceOf(Like.class));
|
||||
return ((Like) exp).right();
|
||||
return ((Like) exp).pattern();
|
||||
}
|
||||
|
||||
private Function function(String name) {
|
||||
|
@ -39,7 +39,7 @@ public class LikeEscapingParsingTests extends ESTestCase {
|
||||
}
|
||||
assertThat(exp, instanceOf(Like.class));
|
||||
Like l = (Like) exp;
|
||||
return l.right();
|
||||
return l.pattern();
|
||||
}
|
||||
|
||||
public void testNoEscaping() {
|
||||
|
@ -33,3 +33,5 @@
|
||||
sort:
|
||||
- int:
|
||||
order: asc
|
||||
missing: _last
|
||||
unmapped_type: long
|
||||
|
@ -74,12 +74,12 @@ public class JdbcDocCsvSpecIT extends SpecBaseIntegrationTestCase {
|
||||
|
||||
@Override
|
||||
protected boolean logEsResultSet() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void doTest() throws Throwable {
|
||||
try (Connection csv = csvConnection(testCase.expectedResults); Connection es = esJdbc()) {
|
||||
try (Connection csv = csvConnection(testCase); Connection es = esJdbc()) {
|
||||
|
||||
// pass the testName as table for debugging purposes (in case the underlying reader is missing)
|
||||
ResultSet expected = executeCsvQuery(csv, testName);
|
||||
|
@ -49,8 +49,7 @@ public abstract class CsvSpecTestCase extends SpecBaseIntegrationTestCase {
|
||||
|
||||
@Override
|
||||
protected final void doTest() throws Throwable {
|
||||
try (Connection csv = csvConnection(testCase.expectedResults);
|
||||
Connection es = esJdbc()) {
|
||||
try (Connection csv = csvConnection(testCase); Connection es = esJdbc()) {
|
||||
|
||||
// pass the testName as table for debugging purposes (in case the underlying reader is missing)
|
||||
ResultSet expected = executeCsvQuery(csv, testName);
|
||||
|
@ -25,7 +25,9 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.arrayWithSize;
|
||||
import static org.hamcrest.Matchers.isEmptyOrNullString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
@ -55,12 +57,12 @@ public final class CsvTestUtils {
|
||||
*
|
||||
* Use {@link #executeCsvQuery} to obtain ResultSet from this connection
|
||||
*/
|
||||
public static Connection csvConnection(String expectedResults) throws IOException, SQLException {
|
||||
public static Connection csvConnection(CsvTestCase csvTest) throws IOException, SQLException {
|
||||
Properties csvProperties = new Properties();
|
||||
csvProperties.setProperty("charset", "UTF-8");
|
||||
csvProperties.setProperty("separator", "|");
|
||||
csvProperties.setProperty("trimValues", "true");
|
||||
Tuple<String, String> resultsAndTypes = extractColumnTypesAndStripCli(expectedResults);
|
||||
Tuple<String, String> resultsAndTypes = extractColumnTypesAndStripCli(csvTest.earlySchema, csvTest.expectedResults);
|
||||
csvProperties.setProperty("columnTypes", resultsAndTypes.v2());
|
||||
Reader reader = new StringReader(resultsAndTypes.v1());
|
||||
TableReader tableReader = new TableReader() {
|
||||
@ -78,7 +80,7 @@ public final class CsvTestUtils {
|
||||
};
|
||||
}
|
||||
|
||||
private static Tuple<String, String> extractColumnTypesAndStripCli(String expectedResults) throws IOException {
|
||||
private static Tuple<String, String> extractColumnTypesAndStripCli(String schema, String expectedResults) throws IOException {
|
||||
try (StringReader reader = new StringReader(expectedResults);
|
||||
BufferedReader bufferedReader = new BufferedReader(reader);
|
||||
StringWriter writer = new StringWriter();
|
||||
@ -87,8 +89,14 @@ public final class CsvTestUtils {
|
||||
String header = bufferedReader.readLine();
|
||||
Tuple<String, String> headerAndTypes;
|
||||
|
||||
String sch = schema;
|
||||
if (header.contains(":")) {
|
||||
headerAndTypes = extractColumnTypesFromHeader(header);
|
||||
assertThat("Cannot declare schema both individually and inside the header", sch, isEmptyOrNullString());
|
||||
sch = header;
|
||||
}
|
||||
|
||||
if (Strings.hasText(sch)) {
|
||||
headerAndTypes = extractColumnTypesFromHeader(sch);
|
||||
} else {
|
||||
// No type information in headers, no need to parse columns - trigger auto-detection
|
||||
headerAndTypes = new Tuple<>(header, "");
|
||||
@ -160,6 +168,9 @@ public final class CsvTestUtils {
|
||||
}
|
||||
|
||||
private static class CsvSpecParser implements SpecBaseIntegrationTestCase.Parser {
|
||||
private static final String SCHEMA_PREFIX = "schema::";
|
||||
|
||||
private final StringBuilder earlySchema = new StringBuilder();
|
||||
private final StringBuilder query = new StringBuilder();
|
||||
private final StringBuilder data = new StringBuilder();
|
||||
private CsvTestCase testCase;
|
||||
@ -168,17 +179,25 @@ public final class CsvTestUtils {
|
||||
public Object parse(String line) {
|
||||
// read the query
|
||||
if (testCase == null) {
|
||||
if (line.endsWith(";")) {
|
||||
if (line.startsWith(SCHEMA_PREFIX)) {
|
||||
assertThat("Early schema already declared " + earlySchema, earlySchema.length(), is(0));
|
||||
earlySchema.append(line.substring(SCHEMA_PREFIX.length()).trim());
|
||||
}
|
||||
else {
|
||||
if (line.endsWith(";")) {
|
||||
// pick up the query
|
||||
testCase = new CsvTestCase();
|
||||
query.append(line.substring(0, line.length() - 1).trim());
|
||||
testCase.query = query.toString();
|
||||
testCase.earlySchema = earlySchema.toString();
|
||||
earlySchema.setLength(0);
|
||||
query.setLength(0);
|
||||
}
|
||||
// keep reading the query
|
||||
else {
|
||||
query.append(line);
|
||||
query.append("\r\n");
|
||||
}
|
||||
// keep reading the query
|
||||
else {
|
||||
query.append(line);
|
||||
query.append("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
// read the results
|
||||
@ -204,6 +223,7 @@ public final class CsvTestUtils {
|
||||
|
||||
public static class CsvTestCase {
|
||||
public String query;
|
||||
public String earlySchema;
|
||||
public String expectedResults;
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,12 @@
|
||||
package org.elasticsearch.xpack.qa.sql.jdbc;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.common.CheckedBiConsumer;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
|
||||
@ -33,7 +33,7 @@ public class DataLoader {
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (RestClient client = RestClient.builder(new HttpHost("localhost", 9200)).build()) {
|
||||
loadEmpDatasetIntoEs(client);
|
||||
Loggers.getLogger(DataLoader.class).info("Data loaded");
|
||||
LogManager.getLogger(DataLoader.class).info("Data loaded");
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +44,6 @@ public class DataLoader {
|
||||
protected static void loadEmpDatasetIntoEs(RestClient client) throws Exception {
|
||||
loadEmpDatasetIntoEs(client, "test_emp", "employees");
|
||||
loadEmpDatasetIntoEs(client, "test_emp_copy", "employees");
|
||||
loadEmpDatasetIntoEs(client, "test_emp_with_nulls", "employees_with_nulls");
|
||||
makeAlias(client, "test_alias", "test_emp", "test_emp_copy");
|
||||
makeAlias(client, "test_alias_emp", "test_emp", "test_emp_copy");
|
||||
}
|
||||
@ -134,12 +133,16 @@ public class DataLoader {
|
||||
bulk.append("{\"index\":{}}\n");
|
||||
bulk.append('{');
|
||||
String emp_no = fields.get(1);
|
||||
|
||||
boolean hadLastItem = false;
|
||||
|
||||
for (int f = 0; f < fields.size(); f++) {
|
||||
// an empty value in the csv file is treated as 'null', thus skipping it in the bulk request
|
||||
if (fields.get(f).trim().length() > 0) {
|
||||
if (f != 0) {
|
||||
bulk.append(',');
|
||||
if (hadLastItem) {
|
||||
bulk.append(",");
|
||||
}
|
||||
hadLastItem = true;
|
||||
bulk.append('"').append(titles.get(f)).append("\":\"").append(fields.get(f)).append('"');
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,7 @@ public abstract class DebugCsvSpec extends SpecBaseIntegrationTestCase {
|
||||
|
||||
@Override
|
||||
protected final void doTest() throws Throwable {
|
||||
try (Connection csv = csvConnection(testCase.expectedResults);
|
||||
Connection es = esJdbc()) {
|
||||
|
||||
try (Connection csv = csvConnection(testCase); Connection es = esJdbc()) {
|
||||
// pass the testName as table for debugging purposes (in case the underlying reader is missing)
|
||||
ResultSet expected = executeCsvQuery(csv, testName);
|
||||
ResultSet elasticResults = executeJdbcQuery(es, testCase.query);
|
||||
|
@ -26,6 +26,7 @@ import static java.sql.Types.REAL;
|
||||
import static java.sql.Types.SMALLINT;
|
||||
import static java.sql.Types.TINYINT;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@ -177,7 +178,12 @@ public class JdbcAssert {
|
||||
|
||||
// handle nulls first
|
||||
if (expectedObject == null || actualObject == null) {
|
||||
assertEquals(msg, expectedObject, actualObject);
|
||||
// hack for JDBC CSV nulls
|
||||
if (expectedObject != null && "null".equals(expectedObject.toString().toLowerCase(Locale.ROOT))) {
|
||||
assertNull(msg, actualObject);
|
||||
} else {
|
||||
assertEquals(msg, expectedObject, actualObject);
|
||||
}
|
||||
}
|
||||
// then timestamp
|
||||
else if (type == Types.TIMESTAMP || type == Types.TIMESTAMP_WITH_TIMEZONE) {
|
||||
|
@ -16,6 +16,22 @@ import java.util.Properties;
|
||||
|
||||
public class LocalH2 extends ExternalResource implements CheckedSupplier<Connection, SQLException> {
|
||||
|
||||
/*
|
||||
* The syntax on the connection string is fairly particular:
|
||||
* mem:; creates an anonymous database in memory. The `;` is
|
||||
* technically the separator that comes after the name.
|
||||
* DATABASE_TO_UPPER=false turns *off* H2's Oracle-like habit
|
||||
* of upper-casing everything that isn't quoted.
|
||||
* ALIAS_COLUMN_NAME=true turn *on* returning alias names in
|
||||
* result set metadata which is what most DBs do except
|
||||
* for MySQL and, by default, H2. Our jdbc driver does it.
|
||||
*/
|
||||
// http://www.h2database.com/html/features.html#in_memory_databases
|
||||
private static String memUrl(String name) {
|
||||
String n = name == null ? "" : name;
|
||||
return "jdbc:h2:mem:" + n + ";DATABASE_TO_UPPER=false;ALIAS_COLUMN_NAME=true";
|
||||
}
|
||||
|
||||
static {
|
||||
try {
|
||||
// Initialize h2 so we can use it for testing
|
||||
@ -30,7 +46,7 @@ public class LocalH2 extends ExternalResource implements CheckedSupplier<Connect
|
||||
* Closing the connection will remove the db.
|
||||
*/
|
||||
public static Connection anonymousDb() throws SQLException {
|
||||
return DriverManager.getConnection("jdbc:h2:mem:;DATABASE_TO_UPPER=false;ALIAS_COLUMN_NAME=true");
|
||||
return DriverManager.getConnection(memUrl(null));
|
||||
}
|
||||
|
||||
private static final Properties DEFAULTS = new Properties();
|
||||
@ -41,19 +57,8 @@ public class LocalH2 extends ExternalResource implements CheckedSupplier<Connect
|
||||
|
||||
private CheckedConsumer<Connection, SQLException> initializer;
|
||||
|
||||
/*
|
||||
* The syntax on the connection string is fairly particular:
|
||||
* mem:; creates an anonymous database in memory. The `;` is
|
||||
* technically the separator that comes after the name.
|
||||
* DATABASE_TO_UPPER=false turns *off* H2's Oracle-like habit
|
||||
* of upper-casing everything that isn't quoted.
|
||||
* ALIAS_COLUMN_NAME=true turn *on* returning alias names in
|
||||
* result set metadata which is what most DBs do except
|
||||
* for MySQL and, by default, H2. Our jdbc driver does it.
|
||||
*/
|
||||
// http://www.h2database.com/html/features.html#in_memory_databases
|
||||
public LocalH2(CheckedConsumer<Connection, SQLException> initializer) {
|
||||
this.url = "jdbc:h2:mem:essql;DATABASE_TO_UPPER=false;ALIAS_COLUMN_NAME=true";
|
||||
this.url = memUrl("essql");
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
@ -76,4 +81,4 @@ public class LocalH2 extends ExternalResource implements CheckedSupplier<Connect
|
||||
public Connection get() throws SQLException {
|
||||
return DriverManager.getConnection(url, DEFAULTS);
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,6 @@ public abstract class SqlSpecTestCase extends SpecBaseIntegrationTestCase {
|
||||
@ClassRule
|
||||
public static LocalH2 H2 = new LocalH2((c) -> {
|
||||
c.createStatement().execute("RUNSCRIPT FROM 'classpath:/setup_test_emp.sql'");
|
||||
c.createStatement().execute("RUNSCRIPT FROM 'classpath:/setup_test_emp_with_nulls.sql'");
|
||||
});
|
||||
|
||||
@ParametersFactory(argumentFormatting = PARAM_FORMATTING)
|
||||
@ -42,7 +41,6 @@ public abstract class SqlSpecTestCase extends SpecBaseIntegrationTestCase {
|
||||
tests.addAll(readScriptSpec("/arithmetic.sql-spec", parser));
|
||||
tests.addAll(readScriptSpec("/string-functions.sql-spec", parser));
|
||||
tests.addAll(readScriptSpec("/case-functions.sql-spec", parser));
|
||||
tests.addAll(readScriptSpec("/agg_nulls.sql-spec", parser));
|
||||
return tests;
|
||||
}
|
||||
|
||||
|
@ -464,7 +464,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> termsScript = (Map<String, Object>) terms.get("script");
|
||||
assertEquals(3, termsScript.size());
|
||||
assertEquals("Math.abs(doc[params.v0].value)", termsScript.get("source"));
|
||||
assertEquals("InternalSqlScriptUtils.abs(InternalSqlScriptUtils.docValue(doc,params.v0))", termsScript.get("source"));
|
||||
assertEquals("painless", termsScript.get("lang"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -494,7 +494,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
||||
}
|
||||
}
|
||||
Collections.sort(aggKeys);
|
||||
assertEquals("having" + aggKeys.get(1), aggFilterKey);
|
||||
assertEquals("having." + aggKeys.get(1), aggFilterKey);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> having = (Map<String, Object>) aggregations2.get(aggFilterKey);
|
||||
@ -513,7 +513,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> filterScript = (Map<String, Object>) bucketSelector.get("script");
|
||||
assertEquals(3, filterScript.size());
|
||||
assertEquals("(params.a0) > (params.v0)", filterScript.get("source"));
|
||||
assertEquals("InternalSqlScriptUtils.gt(params.a0,params.v0)", filterScript.get("source"));
|
||||
assertEquals("painless", filterScript.get("lang"));
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> filterScriptParams = (Map<String, Object>) filterScript.get("params");
|
||||
|
@ -6,64 +6,72 @@ singlePercentileWithoutComma
|
||||
SELECT gender, PERCENTILE(emp_no, 97) p1 FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | p1:d
|
||||
F | 10099.1936
|
||||
M | 10095.6112
|
||||
null |10019.0
|
||||
F |10099.51
|
||||
M |10095.789999999999
|
||||
;
|
||||
|
||||
singlePercentileWithComma
|
||||
SELECT gender, PERCENTILE(emp_no, 97.76) p1 FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | p1:d
|
||||
F | 10099.1936
|
||||
M | 10095.6112
|
||||
null |10019.0
|
||||
F |10099.51
|
||||
M |10095.789999999999
|
||||
;
|
||||
|
||||
multiplePercentilesOneWithCommaOneWithout
|
||||
SELECT gender, PERCENTILE(emp_no, 92.45) p1, PERCENTILE(emp_no, 91) p2 FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | p1:d | p2:d
|
||||
F | 10096.826000000001 | 10094.68
|
||||
M | 10090.319 | 10089.320000000002
|
||||
null |10018.745 |10018.599999999999
|
||||
F |10098.0085 |10096.119999999999
|
||||
M |10091.393 |10090.37
|
||||
;
|
||||
|
||||
multiplePercentilesWithoutComma
|
||||
SELECT gender, PERCENTILE(emp_no, 91) p1, PERCENTILE(emp_no, 89) p2 FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | p1:d | p2:d
|
||||
F | 10094.68 | 10092.08
|
||||
M | 10089.320000000002 | 10085.18
|
||||
null |10018.599999999999 |10018.4
|
||||
F |10096.119999999999 |10093.74
|
||||
M |10090.37 |10086.92
|
||||
;
|
||||
|
||||
multiplePercentilesWithComma
|
||||
SELECT gender, PERCENTILE(emp_no, 85.7) p1, PERCENTILE(emp_no, 94.3) p2 FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | p1:d | p2:d
|
||||
F | 10088.852 | 10097.792
|
||||
M | 10083.134 | 10091.932
|
||||
null |10018.070000000002 |10018.929999999998
|
||||
F |10091.343 |10098.619
|
||||
M |10084.349 |10093.502
|
||||
;
|
||||
|
||||
percentileRank
|
||||
SELECT gender, PERCENTILE_RANK(emp_no, 10025) rank FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | rank:d
|
||||
F | 26.351351351351347
|
||||
M | 23.41269841269841
|
||||
null |100.0
|
||||
F |17.424242424242426
|
||||
M |15.350877192982457
|
||||
;
|
||||
|
||||
multiplePercentileRanks
|
||||
SELECT gender, PERCENTILE_RANK(emp_no, 10030.0) rank1, PERCENTILE_RANK(emp_no, 10025) rank2 FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | rank1:d | rank2:d
|
||||
F | 29.93762993762994 | 26.351351351351347
|
||||
M | 29.365079365079367 | 23.41269841269841
|
||||
null |100.0 |100.0
|
||||
F |21.445221445221442 |17.424242424242426
|
||||
M |21.929824561403507 |15.350877192982457
|
||||
;
|
||||
|
||||
multiplePercentilesAndPercentileRank
|
||||
SELECT gender, PERCENTILE(emp_no, 97.76) p1, PERCENTILE(emp_no, 93.3) p2, PERCENTILE_RANK(emp_no, 10025) rank FROM test_emp GROUP BY gender;
|
||||
|
||||
gender:s | p1:d | p2:d | rank:d
|
||||
F | 10099.1936 | 10098.021 | 26.351351351351347
|
||||
M | 10095.6112 | 10090.846 | 23.41269841269841
|
||||
null |10019.0 |10018.83 |100.0
|
||||
F |10099.7608 |10098.289 |17.424242424242426
|
||||
M |10096.2232 |10092.362 |15.350877192982457
|
||||
;
|
||||
|
||||
sum
|
||||
@ -110,6 +118,7 @@ SELECT gender, KURTOSIS(salary) k, SKEWNESS(salary) s FROM test_emp GROUP BY gen
|
||||
|
||||
gender:s | k:d | s:d
|
||||
|
||||
F | 1.8427808415250482 | 0.04517149340491813
|
||||
M | 2.259327644285826 | 0.40268950715550333
|
||||
null |2.2215791166941923 |-0.03373126000214023
|
||||
F |1.7873117044424276 |0.05504995122217512
|
||||
M |2.280646181070106 |0.44302407229580243
|
||||
;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user