From 024c07925ea7b427271231aca78fc70d77bb2cad Mon Sep 17 00:00:00 2001
From: Igor Motov <igor@motovs.org>
Date: Fri, 2 Nov 2018 17:04:33 -0400
Subject: [PATCH 1/4] SQL: Add ST_WktToSQL function

Adds support for ST_WktToSQL function which accepts a string and parses
it as WKT representation of a geoshape.

Relates to #29872
---
 docs/reference/sql/functions/geo.asciidoc     | 25 +++++++
 .../qa/src/main/resources/command.csv-spec    |  1 +
 .../sql/qa/src/main/resources/docs.csv-spec   |  1 +
 .../qa/src/main/resources/geo/docs.csv-spec   | 11 +++-
 .../qa/src/main/resources/geo/geosql.csv-spec | 29 +++++++++
 .../expression/function/FunctionRegistry.java |  2 +
 .../function/scalar/Processors.java           |  2 +
 .../function/scalar/geo/StWkttosql.java       | 65 +++++++++++++++++++
 .../scalar/geo/StWkttosqlProcessor.java       | 57 ++++++++++++++++
 .../whitelist/InternalSqlScriptUtils.java     |  6 ++
 .../xpack/sql/type/DataTypes.java             |  4 ++
 .../xpack/sql/plugin/sql_whitelist.txt        | 10 ++-
 12 files changed, 211 insertions(+), 2 deletions(-)
 create mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosql.java
 create mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java

diff --git a/docs/reference/sql/functions/geo.asciidoc b/docs/reference/sql/functions/geo.asciidoc
index af47ebd2c7de0..14bd5fad92c4b 100644
--- a/docs/reference/sql/functions/geo.asciidoc
+++ b/docs/reference/sql/functions/geo.asciidoc
@@ -30,3 +30,28 @@ Returns the WKT representation of the `geometry`. The return type is string.
 --------------------------------------------------
 include-tagged::{sql-specs}/geo/docs.csv-spec[aswkt]
 --------------------------------------------------
+
+
+[[sql-functions-geo-st-as-wkt]]
+===== `ST_AsWKT`
+
+.Synopsis:
+[source, sql]
+--------------------------------------------------
+ST_WKTToSQL(string<1>)
+--------------------------------------------------
+
+*Input*:
+
+<1> string geometry
+
+*Output*: WKT string
+
+.Description:
+
+Returns the geometry from WKT representation. The return type is geometry.
+
+["source","sql",subs="attributes,macros"]
+--------------------------------------------------
+include-tagged::{sql-specs}/geo/docs.csv-spec[aswkt]
+--------------------------------------------------
\ No newline at end of file
diff --git a/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec
index 8588390405eca..5660bf93f740e 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec
@@ -101,6 +101,7 @@ SPACE           |SCALAR
 SUBSTRING       |SCALAR
 UCASE           |SCALAR
 ST_ASWKT        |SCALAR
+ST_WKTTOSQL     |SCALAR
 CAST            |SCALAR
 CONVERT         |SCALAR
 SCORE           |SCORE
diff --git a/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec
index 72046a982a408..9c52de592caa2 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec
@@ -278,6 +278,7 @@ SPACE           |SCALAR
 SUBSTRING       |SCALAR
 UCASE           |SCALAR         
 ST_ASWKT        |SCALAR
+ST_WKTTOSQL     |SCALAR
 CAST            |SCALAR
 CONVERT         |SCALAR
 SCORE           |SCORE
diff --git a/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
index 2216a43f68c14..a288113375188 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
@@ -10,9 +10,18 @@
 
 selectAsWKT
 // tag::aswkt
-SELECT city, ST_ASWKT(location) location FROM "geo" WHERE city = 'Amsterdam';
+SELECT city, ST_AsWKT(location) location FROM "geo" WHERE city = 'Amsterdam';
 
      city:s    |     location:s
 Amsterdam      |point (4.850311987102032 52.347556999884546)
 // end::aswkt
 ;
+
+selectAsWKT
+// tag::wkttosql
+SELECT ST_AsWKT(ST_WKTToSQL('POINT (10 20)')) location;
+
+   location:s
+point (10.0 20.0)
+// end::wkttosql
+;
diff --git a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec
index ce58a112488ce..989fe76f7cc1e 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec
@@ -102,3 +102,32 @@ SELECT COUNT(city) count, CAST(SUBSTRING(ST_ASWKT(location), 8, 1) = '-' AS STRI
 9              |false
 6              |true
 ;
+
+selectFakeCoordinatesFromCityAndRegion
+SELECT region, city, ST_ASWKT(ST_WKTTOSQL(CONCAT(CONCAT(CONCAT(CONCAT('POINT (', CAST(LENGTH(city) AS STRING)), ' '), CAST(LENGTH(region) AS STRING)), ')'))) loc  FROM geo ORDER BY region, city;
+
+   region:s    |    city:s     |       loc:s
+Americas       |Chicago        |point (7.0 8.0)
+Americas       |Mountain View  |point (13.0 8.0)
+Americas       |New York       |point (8.0 8.0)
+Americas       |Phoenix        |point (7.0 8.0)
+Americas       |San Francisco  |point (13.0 8.0)
+Asia           |Hong Kong      |point (9.0 4.0)
+Asia           |Seoul          |point (5.0 4.0)
+Asia           |Singapore      |point (9.0 4.0)
+Asia           |Sydney         |point (6.0 4.0)
+Asia           |Tokyo          |point (5.0 4.0)
+Europe         |Amsterdam      |point (9.0 6.0)
+Europe         |Berlin         |point (6.0 6.0)
+Europe         |London         |point (6.0 6.0)
+Europe         |Munich         |point (6.0 6.0)
+Europe         |Paris          |point (5.0 6.0)
+;
+
+selectAllPointsGroupByHemisphereFromAsWKT
+SELECT COUNT(city) count, CAST(SUBSTRING(ST_ASWKT(ST_WKTTOSQL(UCASE(ST_ASWKT(location)))), 8, 1) = '-' AS STRING) west FROM "geo" GROUP BY west ORDER BY west;
+
+    count:l    |  west:s
+9              |false
+6              |true
+;
\ No newline at end of file
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java
index e44edafd9b03b..b563c4b4c8d5f 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java
@@ -35,6 +35,7 @@
 import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.WeekOfYear;
 import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Year;
 import org.elasticsearch.xpack.sql.expression.function.scalar.geo.StAswkt;
+import org.elasticsearch.xpack.sql.expression.function.scalar.geo.StWkttosql;
 import org.elasticsearch.xpack.sql.expression.function.scalar.math.ACos;
 import org.elasticsearch.xpack.sql.expression.function.scalar.math.ASin;
 import org.elasticsearch.xpack.sql.expression.function.scalar.math.ATan;
@@ -215,6 +216,7 @@ private void defineDefaultFunctions() {
 
         // Geo Functions
         addToMap(def(StAswkt.class, StAswkt::new));
+        addToMap(def(StWkttosql.class, StWkttosql::new));
         // DataType conversion
         addToMap(def(Cast.class, Cast::new, "CONVERT"));
         // Special
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Processors.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Processors.java
index 0ed87eb78d7f1..730477d3a1e7c 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Processors.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Processors.java
@@ -11,6 +11,7 @@
 import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor;
 import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor;
 import org.elasticsearch.xpack.sql.expression.function.scalar.geo.GeoProcessor;
+import org.elasticsearch.xpack.sql.expression.function.scalar.geo.StWkttosqlProcessor;
 import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor;
 import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor;
 import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringNumericProcessor;
@@ -90,6 +91,7 @@ public static List<NamedWriteableRegistry.Entry> getNamedWriteables() {
         entries.add(new Entry(Processor.class, ReplaceFunctionProcessor.NAME, ReplaceFunctionProcessor::new));
         entries.add(new Entry(Processor.class, SubstringFunctionProcessor.NAME, SubstringFunctionProcessor::new));
         entries.add(new Entry(Processor.class, GeoProcessor.NAME, GeoProcessor::new));
+        entries.add(new Entry(Processor.class, StWkttosqlProcessor.NAME, StWkttosqlProcessor::new));
         return entries;
     }
 
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosql.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosql.java
new file mode 100644
index 0000000000000..e396e17a8648e
--- /dev/null
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosql.java
@@ -0,0 +1,65 @@
+/*
+ * 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.geo;
+
+import org.elasticsearch.xpack.sql.expression.Expression;
+import org.elasticsearch.xpack.sql.expression.Expressions;
+import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
+import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
+import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
+import org.elasticsearch.xpack.sql.tree.Location;
+import org.elasticsearch.xpack.sql.tree.NodeInfo;
+import org.elasticsearch.xpack.sql.type.DataType;
+
+/**
+ * Constructs geometric objects from their WTK representations
+ */
+public class StWkttosql extends UnaryScalarFunction {
+
+    public StWkttosql(Location location, Expression field) {
+        super(location, field);
+    }
+
+    @Override
+    protected StWkttosql replaceChild(Expression newChild) {
+        return new StWkttosql(location(), newChild);
+    }
+
+    @Override
+    protected TypeResolution resolveType() {
+        if (field().dataType().isString()) {
+            return TypeResolution.TYPE_RESOLVED;
+        }
+        return Expressions.typeMustBeString(field(), functionName(), Expressions.ParamOrdinal.DEFAULT);
+    }
+
+    @Override
+    protected Processor makeProcessor() {
+        return StWkttosqlProcessor.INSTANCE;
+    }
+
+    @Override
+    public DataType dataType() {
+        return DataType.GEO_SHAPE;
+    }
+
+    @Override
+    protected NodeInfo<StWkttosql> info() {
+        return NodeInfo.create(this, StWkttosql::new, field());
+    }
+
+    @Override
+    public String processScript(String script) {
+        return Scripts.formatTemplate(Scripts.SQL_SCRIPTS + ".wktToSql(" + script + ")");
+    }
+
+    @Override
+    public Object fold() {
+        return StWkttosqlProcessor.INSTANCE.process(field().fold());
+    }
+
+}
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java
new file mode 100644
index 0000000000000..33441532ac796
--- /dev/null
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java
@@ -0,0 +1,57 @@
+/*
+ * 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.geo;
+
+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.Processor;
+
+import java.io.IOException;
+
+public class StWkttosqlProcessor implements Processor {
+
+    static final StWkttosqlProcessor INSTANCE = new StWkttosqlProcessor();
+
+    public static final String NAME = "geo_wkttosql";
+
+    private StWkttosqlProcessor() {
+    }
+
+    public StWkttosqlProcessor(StreamInput in) throws IOException {}
+
+    @Override
+    public Object process(Object input) {
+        return StWkttosqlProcessor.apply(input);
+    }
+
+
+    public static GeoShape apply(Object input) {
+        if (input == null) {
+            return null;
+        }
+
+        if ((input instanceof String) == false) {
+            throw new SqlIllegalArgumentException("A string is required; received {}", input);
+        }
+        try {
+            return new GeoShape(input);
+        } catch (IOException ex) {
+            throw new SqlIllegalArgumentException("Cannot parse [{}] as a geo_shape value", input);
+        }
+    }
+
+    @Override
+    public String getWriteableName() {
+        return NAME;
+    }
+
+    @Override
+    public void writeTo(StreamOutput out) throws IOException {
+
+    }
+}
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java
index be961aae99b57..7c778054a0be0 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java
@@ -12,6 +12,8 @@
 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.geo.GeoProcessor;
+import org.elasticsearch.xpack.sql.expression.function.scalar.geo.GeoShape;
+import org.elasticsearch.xpack.sql.expression.function.scalar.geo.StWkttosqlProcessor;
 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;
@@ -403,4 +405,8 @@ public static String aswktPoint(Object v) {
     public static String aswktShape(Object v) {
         return GeoProcessor.GeoOperation.ASWKT_SHAPE.apply(v).toString();
     }
+
+    public static GeoShape wktToSql(String v) {
+        return StWkttosqlProcessor.apply(v);
+    }
 }
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/DataTypes.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/DataTypes.java
index 92bc6f33a5de5..d293422dfeb02 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/DataTypes.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/type/DataTypes.java
@@ -6,6 +6,7 @@
 package org.elasticsearch.xpack.sql.type;
 
 import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
+import org.elasticsearch.xpack.sql.expression.function.scalar.geo.GeoShape;
 import org.joda.time.DateTime;
 
 public final class DataTypes {
@@ -51,6 +52,9 @@ public static DataType fromJava(Object value) {
         if (value instanceof String || value instanceof Character) {
             return DataType.KEYWORD;
         }
+        if (value instanceof GeoShape) {
+            return DataType.GEO_SHAPE;
+        }
         throw new SqlIllegalArgumentException("No idea what's the DataType for {}", value.getClass());
     }
 
diff --git a/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt b/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt
index fb37745d154ba..2794a2ff9e11d 100644
--- a/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt
+++ b/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt
@@ -4,7 +4,14 @@
 # you may not use this file except in compliance with the Elastic License.
 #
 
-# This file contains a whitelist for SQL specific utilities available inside SQL scripting
+# This file contains a whitelist for SQL specific utilities and classes available inside SQL scripting
+
+#### Classes
+
+class org.elasticsearch.xpack.sql.expression.function.scalar.geo.GeoShape {
+
+}
+
 
 class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalSqlScriptUtils {
 
@@ -116,4 +123,5 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS
   String  ucase(String)
   String aswktPoint(Object)
   String aswktShape(Object)
+  GeoShape wktToSql(String)
 }

From ed0aa6c692083e977ef75e1a00c0745547c7ed78 Mon Sep 17 00:00:00 2001
From: Igor Motov <igor@motovs.org>
Date: Mon, 12 Nov 2018 18:32:53 -0500
Subject: [PATCH 2/4] Address review comments and add some JDBC tests

---
 .../qa/src/main/resources/command.csv-spec    |  2 +
 .../sql/qa/src/main/resources/docs.csv-spec   |  2 +
 .../qa/src/main/resources/geo/docs.csv-spec   |  2 +-
 .../src/main/resources/geo/geosql-bulk.json   | 30 ++++-----
 .../qa/src/main/resources/geo/geosql.csv-spec | 64 ++++++++++++-------
 .../sql/qa/src/main/resources/geo/geosql.json |  3 +
 .../qa/src/main/resources/ogc/ogc.sql-spec    | 12 ++++
 .../expression/function/FunctionRegistry.java |  4 +-
 .../scalar/geo/StWkttosqlProcessor.java       | 11 ++--
 .../whitelist/InternalSqlScriptUtils.java     |  4 +-
 .../scalar/geo/StWkttosqlProcessorTests.java  | 42 ++++++++++++
 11 files changed, 127 insertions(+), 49 deletions(-)
 create mode 100644 x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessorTests.java

diff --git a/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec
index 5660bf93f740e..34e8e1fbf1967 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/command.csv-spec
@@ -100,7 +100,9 @@ RTRIM           |SCALAR
 SPACE           |SCALAR         
 SUBSTRING       |SCALAR
 UCASE           |SCALAR
+ST_ASTEXT       |SCALAR
 ST_ASWKT        |SCALAR
+ST_GEOMFROMTEXT |SCALAR
 ST_WKTTOSQL     |SCALAR
 CAST            |SCALAR
 CONVERT         |SCALAR
diff --git a/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec
index 9c52de592caa2..437c66a4ea199 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/docs.csv-spec
@@ -277,7 +277,9 @@ RTRIM           |SCALAR
 SPACE           |SCALAR         
 SUBSTRING       |SCALAR
 UCASE           |SCALAR         
+ST_ASTEXT       |SCALAR
 ST_ASWKT        |SCALAR
+ST_GEOMFROMTEXT |SCALAR
 ST_WKTTOSQL     |SCALAR
 CAST            |SCALAR
 CONVERT         |SCALAR
diff --git a/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
index a288113375188..9bfd01ce9345c 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
@@ -17,7 +17,7 @@ Amsterdam      |point (4.850311987102032 52.347556999884546)
 // end::aswkt
 ;
 
-selectAsWKT
+selectWKTToSQL
 // tag::wkttosql
 SELECT ST_AsWKT(ST_WKTToSQL('POINT (10 20)')) location;
 
diff --git a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql-bulk.json b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql-bulk.json
index 56c76b9f769f3..7840c10150881 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql-bulk.json
+++ b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql-bulk.json
@@ -1,33 +1,33 @@
 {"index":{"_id": "1"}}
-{"region": "Americas", "city": "Mountain View", "location": {"lat":"37.386483", "lon":"-122.083843"}, "shape": "POINT (-122.083843 37.386483)"}
+{"region": "Americas", "city": "Mountain View", "location": {"lat":"37.386483", "lon":"-122.083843"}, "shape": "POINT (-122.083843 37.386483)", "region_point": "POINT(-105.2551 54.5260)"}
 {"index":{"_id": "2"}}
-{"region": "Americas", "city": "Chicago", "location": [-87.637874, 41.888783], "shape": {"type" : "point", "coordinates" : [-87.637874, 41.888783] }}
+{"region": "Americas", "city": "Chicago", "location": [-87.637874, 41.888783], "shape": {"type" : "point", "coordinates" : [-87.637874, 41.888783]}, "region_point": "POINT(-105.2551 54.5260)"}
 {"index":{"_id": "3"}}
-{"region": "Americas", "city": "New York", "location": "40.745171,-73.990027", "shape": "POINT (-73.990027 40.745171)"}
+{"region": "Americas", "city": "New York", "location": "40.745171,-73.990027", "shape": "POINT (-73.990027 40.745171)", "region_point": "POINT(-105.2551 54.5260)"}
 {"index":{"_id": "4"}}
-{"region": "Americas", "city": "San Francisco", "location": "37.789541,-122.394228", "shape": "POINT (-122.394228 37.789541)"}
+{"region": "Americas", "city": "San Francisco", "location": "37.789541,-122.394228", "shape": "POINT (-122.394228 37.789541)", "region_point": "POINT(-105.2551 54.5260)"}
 {"index":{"_id": "5"}}
-{"region": "Americas", "city": "Phoenix", "location": "33.376242,-111.973505", "shape": "POINT (-111.973505 33.376242)"}
+{"region": "Americas", "city": "Phoenix", "location": "33.376242,-111.973505", "shape": "POINT (-111.973505 33.376242)", "region_point": "POINT(-105.2551 54.5260)"}
 {"index":{"_id": "6"}}
-{"region": "Europe", "city": "Amsterdam", "location": "52.347557,4.850312", "shape": "POINT (4.850312 52.347557)"}
+{"region": "Europe", "city": "Amsterdam", "location": "52.347557,4.850312", "shape": "POINT (4.850312 52.347557)", "region_point": "POINT(15.2551 54.5260)"}
 {"index":{"_id": "7"}}
-{"region": "Europe", "city": "Berlin", "location": "52.486701,13.390889", "shape": "POINT (13.390889 52.486701)"}
+{"region": "Europe", "city": "Berlin", "location": "52.486701,13.390889", "shape": "POINT (13.390889 52.486701)", "region_point": "POINT(15.2551 54.5260)"}
 {"index":{"_id": "8"}}
-{"region": "Europe", "city": "Munich", "location": "48.146321,11.537505", "shape": "POINT (11.537505 48.146321)"}
+{"region": "Europe", "city": "Munich", "location": "48.146321,11.537505", "shape": "POINT (11.537505 48.146321)", "region_point": "POINT(15.2551 54.5260)"}
 {"index":{"_id": "9"}}
-{"region": "Europe", "city": "London", "location": "51.510871,-0.121672", "shape": "POINT (-0.121672 51.510871)"}
+{"region": "Europe", "city": "London", "location": "51.510871,-0.121672", "shape": "POINT (-0.121672 51.510871)", "region_point": "POINT(15.2551 54.5260)"}
 {"index":{"_id": "10"}}
-{"region": "Europe", "city": "Paris", "location": "48.845538,2.351773", "shape": "POINT (2.351773 48.845538)"}
+{"region": "Europe", "city": "Paris", "location": "48.845538,2.351773", "shape": "POINT (2.351773 48.845538)", "region_point": "POINT(15.2551 54.5260)"}
 {"index":{"_id": "11"}}
-{"region": "Asia", "city": "Singapore", "location": "1.295868,103.855535", "shape": "POINT (103.855535 1.295868)"}
+{"region": "Asia", "city": "Singapore", "location": "1.295868,103.855535", "shape": "POINT (103.855535 1.295868)", "region_point": "POINT(100.6197 34.0479)"}
 {"index":{"_id": "12"}}
-{"region": "Asia", "city": "Hong Kong", "location": "22.281397,114.183925", "shape": "POINT (114.183925 22.281397)"}
+{"region": "Asia", "city": "Hong Kong", "location": "22.281397,114.183925", "shape": "POINT (114.183925 22.281397)", "region_point": "POINT(100.6197 34.0479)"}
 {"index":{"_id": "13"}}
-{"region": "Asia", "city": "Seoul", "location": "37.509132,127.060851", "shape": "POINT (127.060851 37.509132)"}
+{"region": "Asia", "city": "Seoul", "location": "37.509132,127.060851", "shape": "POINT (127.060851 37.509132)", "region_point": "POINT(100.6197 34.0479)"}
 {"index":{"_id": "14"}}
-{"region": "Asia", "city": "Tokyo", "location": "35.669616,139.76402225", "shape": "POINT (139.76402225 35.669616)"}
+{"region": "Asia", "city": "Tokyo", "location": "35.669616,139.76402225", "shape": "POINT (139.76402225 35.669616)", "region_point": "POINT(100.6197 34.0479)"}
 {"index":{"_id": "15"}}
-{"region": "Asia", "city": "Sydney", "location": "-33.863385,151.208629", "shape": "POINT (151.208629 -33.863385)"}
+{"region": "Asia", "city": "Sydney", "location": "-33.863385,151.208629", "shape": "POINT (151.208629 -33.863385)", "region_point": "POINT(100.6197 34.0479)"}
 
 
 
diff --git a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec
index 989fe76f7cc1e..7ec42197efa5a 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.csv-spec
@@ -18,6 +18,7 @@ DESCRIBE "geo";
 city                 | VARCHAR    | KEYWORD
 location             | OTHER      | GEO_POINT
 region               | VARCHAR    | KEYWORD
+region_point         | VARCHAR    | KEYWORD
 shape                | OTHER      | GEO_SHAPE
 ;
 
@@ -103,31 +104,46 @@ SELECT COUNT(city) count, CAST(SUBSTRING(ST_ASWKT(location), 8, 1) = '-' AS STRI
 6              |true
 ;
 
-selectFakeCoordinatesFromCityAndRegion
-SELECT region, city, ST_ASWKT(ST_WKTTOSQL(CONCAT(CONCAT(CONCAT(CONCAT('POINT (', CAST(LENGTH(city) AS STRING)), ' '), CAST(LENGTH(region) AS STRING)), ')'))) loc  FROM geo ORDER BY region, city;
-
-   region:s    |    city:s     |       loc:s
-Americas       |Chicago        |point (7.0 8.0)
-Americas       |Mountain View  |point (13.0 8.0)
-Americas       |New York       |point (8.0 8.0)
-Americas       |Phoenix        |point (7.0 8.0)
-Americas       |San Francisco  |point (13.0 8.0)
-Asia           |Hong Kong      |point (9.0 4.0)
-Asia           |Seoul          |point (5.0 4.0)
-Asia           |Singapore      |point (9.0 4.0)
-Asia           |Sydney         |point (6.0 4.0)
-Asia           |Tokyo          |point (5.0 4.0)
-Europe         |Amsterdam      |point (9.0 6.0)
-Europe         |Berlin         |point (6.0 6.0)
-Europe         |London         |point (6.0 6.0)
-Europe         |Munich         |point (6.0 6.0)
-Europe         |Paris          |point (5.0 6.0)
+selectRegionUsingWktToSql
+SELECT region, city, ST_ASWKT(ST_WKTTOSQL(region_point)) region_wkt  FROM geo ORDER BY region, city;
+
+   region:s    |    city:s     |       region_wkt:s
+Americas       |Chicago        |point (-105.2551 54.526)
+Americas       |Mountain View  |point (-105.2551 54.526)
+Americas       |New York       |point (-105.2551 54.526)
+Americas       |Phoenix        |point (-105.2551 54.526)
+Americas       |San Francisco  |point (-105.2551 54.526)
+Asia           |Hong Kong      |point (100.6197 34.0479)
+Asia           |Seoul          |point (100.6197 34.0479)
+Asia           |Singapore      |point (100.6197 34.0479)
+Asia           |Sydney         |point (100.6197 34.0479)
+Asia           |Tokyo          |point (100.6197 34.0479)
+Europe         |Amsterdam      |point (15.2551 54.526)
+Europe         |Berlin         |point (15.2551 54.526)
+Europe         |London         |point (15.2551 54.526)
+Europe         |Munich         |point (15.2551 54.526)
+Europe         |Paris          |point (15.2551 54.526)
 ;
 
-selectAllPointsGroupByHemisphereFromAsWKT
-SELECT COUNT(city) count, CAST(SUBSTRING(ST_ASWKT(ST_WKTTOSQL(UCASE(ST_ASWKT(location)))), 8, 1) = '-' AS STRING) west FROM "geo" GROUP BY west ORDER BY west;
+selectCitiesWithAGroupByWktToSql
+SELECT COUNT(city) city_by_region, CAST(ST_WKTTOSQL(region_point) AS STRING) region FROM geo WHERE city LIKE '%a%' GROUP BY ST_WKTTOSQL(region_point) ORDER BY ST_WKTTOSQL(region_point);
 
-    count:l    |  west:s
-9              |false
-6              |true
+ city_by_region:l    |       region:s
+3                    |point (-105.2551 54.526)
+1                    |point (100.6197 34.0479)
+2                    |point (15.2551 54.526)
+;
+
+selectCitiesWithEOrderByWktToSql
+SELECT region, city FROM geo WHERE city LIKE '%e%' ORDER BY ST_WKTTOSQL(region_point), city;
+
+   region:s    |    city:s
+Americas       |Mountain View
+Americas       |New York
+Americas       |Phoenix
+Asia           |Seoul
+Asia           |Singapore
+Asia           |Sydney
+Europe         |Amsterdam
+Europe         |Berlin
 ;
\ No newline at end of file
diff --git a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.json b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.json
index d60910d098b40..05abbe6bb1e03 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.json
+++ b/x-pack/plugin/sql/qa/src/main/resources/geo/geosql.json
@@ -16,6 +16,9 @@
         },
         "shape": {
           "type": "geo_shape"
+        },
+        "region_point": {
+          "type": "keyword"
         }
       }
     }
diff --git a/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec b/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec
index effcb8c90910a..0bb78fa10a04f 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/ogc/ogc.sql-spec
@@ -22,3 +22,15 @@ selectNamedPlaces
 SELECT fid, name, boundary FROM named_places ORDER BY fid;
 selectMapNeatLines
 SELECT fid, neatline FROM map_neatlines ORDER BY fid;
+
+//
+// Type conversion functions
+//
+
+// The string serialization is slightly different between ES and H2, so we need to tweak it a bit by uppercasing both
+// and removing floating point
+selectRoadSegmentsAsWkt
+SELECT fid, name, num_lanes, aliases, REPLACE(UCASE(ST_AsText(centerline)), '.0', '') centerline_wkt FROM road_segments ORDER BY fid;
+
+selectSinglePoint
+SELECT ST_GeomFromText('point (10.0 12.0)') point;
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java
index b563c4b4c8d5f..b32e2a2a31a1a 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java
@@ -215,8 +215,8 @@ private void defineDefaultFunctions() {
                 def(UCase.class, UCase::new));
 
         // Geo Functions
-        addToMap(def(StAswkt.class, StAswkt::new));
-        addToMap(def(StWkttosql.class, StWkttosql::new));
+        addToMap(def(StAswkt.class, StAswkt::new, "ST_ASTEXT"));
+        addToMap(def(StWkttosql.class, StWkttosql::new, "ST_GEOMFROMTEXT"));
         // DataType conversion
         addToMap(def(Cast.class, Cast::new, "CONVERT"));
         // Special
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java
index 33441532ac796..83d9ce9c132a7 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessor.java
@@ -6,6 +6,7 @@
 
 package org.elasticsearch.xpack.sql.expression.function.scalar.geo;
 
+import org.elasticsearch.ElasticsearchParseException;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
@@ -19,28 +20,28 @@ public class StWkttosqlProcessor implements Processor {
 
     public static final String NAME = "geo_wkttosql";
 
-    private StWkttosqlProcessor() {
+    StWkttosqlProcessor() {
     }
 
-    public StWkttosqlProcessor(StreamInput in) throws IOException {}
+    public StWkttosqlProcessor(StreamInput in) throws IOException {
+    }
 
     @Override
     public Object process(Object input) {
         return StWkttosqlProcessor.apply(input);
     }
 
-
     public static GeoShape apply(Object input) {
         if (input == null) {
             return null;
         }
 
         if ((input instanceof String) == false) {
-            throw new SqlIllegalArgumentException("A string is required; received {}", input);
+            throw new SqlIllegalArgumentException("A string is required; received [{}]", input);
         }
         try {
             return new GeoShape(input);
-        } catch (IOException ex) {
+        } catch (IOException | IllegalArgumentException | ElasticsearchParseException ex) {
             throw new SqlIllegalArgumentException("Cannot parse [{}] as a geo_shape value", input);
         }
     }
diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java
index 7c778054a0be0..25cf92d3589be 100644
--- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java
+++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java
@@ -406,7 +406,7 @@ public static String aswktShape(Object v) {
         return GeoProcessor.GeoOperation.ASWKT_SHAPE.apply(v).toString();
     }
 
-    public static GeoShape wktToSql(String v) {
-        return StWkttosqlProcessor.apply(v);
+    public static GeoShape wktToSql(String wktString) {
+        return StWkttosqlProcessor.apply(wktString);
     }
 }
diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessorTests.java
new file mode 100644
index 0000000000000..fc7b33ae905d7
--- /dev/null
+++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/scalar/geo/StWkttosqlProcessorTests.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+package org.elasticsearch.xpack.sql.expression.function.scalar.geo;
+
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
+
+import static org.hamcrest.Matchers.instanceOf;
+
+public class StWkttosqlProcessorTests extends ESTestCase {
+    public static StWkttosqlProcessor randomStWkttosqlProcessor() {
+        return new StWkttosqlProcessor();
+    }
+
+    public void testApply() {
+        StWkttosqlProcessor proc = new StWkttosqlProcessor();
+        assertNull(proc.process(null));
+        Object result = proc.process("POINT (10 20)");
+        assertThat(result, instanceOf(GeoShape.class));
+        GeoShape geoShape = (GeoShape) result;
+        assertEquals("point (10.0 20.0)", geoShape.toString());
+    }
+
+    public void testTypeCheck() {
+        StWkttosqlProcessor procPoint = new StWkttosqlProcessor();
+        SqlIllegalArgumentException siae = expectThrows(SqlIllegalArgumentException.class, () -> procPoint.process(42));
+        assertEquals("A string is required; received [42]", siae.getMessage());
+
+        siae = expectThrows(SqlIllegalArgumentException.class, () -> procPoint.process("some random string"));
+        assertEquals("Cannot parse [some random string] as a geo_shape value", siae.getMessage());
+
+        siae = expectThrows(SqlIllegalArgumentException.class, () -> procPoint.process("point (foo bar)"));
+        assertEquals("Cannot parse [point (foo bar)] as a geo_shape value", siae.getMessage());
+
+
+        siae = expectThrows(SqlIllegalArgumentException.class, () -> procPoint.process("point (10 10"));
+        assertEquals("Cannot parse [point (10 10] as a geo_shape value", siae.getMessage());
+    }
+}

From 68c6fa028c0e550e131f044050c323c9493a0fd8 Mon Sep 17 00:00:00 2001
From: Igor Motov <igor@motovs.org>
Date: Tue, 13 Nov 2018 10:46:13 -0500
Subject: [PATCH 3/4] Cast geoshape in docs instead of using ST_AsWKT

---
 x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec b/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
index 9bfd01ce9345c..4444a86e233c8 100644
--- a/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
+++ b/x-pack/plugin/sql/qa/src/main/resources/geo/docs.csv-spec
@@ -19,7 +19,7 @@ Amsterdam      |point (4.850311987102032 52.347556999884546)
 
 selectWKTToSQL
 // tag::wkttosql
-SELECT ST_AsWKT(ST_WKTToSQL('POINT (10 20)')) location;
+SELECT CAST(ST_WKTToSQL('POINT (10 20)') AS STRING) location;
 
    location:s
 point (10.0 20.0)

From 3be14f9e0b5036a461b4387b0d19205daf16cd3d Mon Sep 17 00:00:00 2001
From: Igor Motov <igor@motovs.org>
Date: Tue, 13 Nov 2018 12:36:21 -0500
Subject: [PATCH 4/4] Add QueryTranslatorTests

---
 .../analyzer/FieldAttributeTests.java         |  4 +-
 .../logical/command/sys/SysColumnsTests.java  | 12 ++++-
 .../sql/planner/QueryTranslatorTests.java     | 53 +++++++++++++++++++
 .../mapping-multi-field-variation.json        |  2 +
 4 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/FieldAttributeTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/FieldAttributeTests.java
index 9d05d151359fd..dbdadad3a2718 100644
--- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/FieldAttributeTests.java
+++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/FieldAttributeTests.java
@@ -153,7 +153,7 @@ public void testDottedFieldPathTypo() {
     public void testStarExpansionExcludesObjectAndUnsupportedTypes() {
         LogicalPlan plan = plan("SELECT * FROM test");
         List<? extends NamedExpression> list = ((Project) plan).projections();
-        assertThat(list, hasSize(8));
+        assertThat(list, hasSize(10));
         List<String> names = Expressions.names(list);
         assertThat(names, not(hasItem("some")));
         assertThat(names, not(hasItem("some.dotted")));
@@ -194,4 +194,4 @@ public void testFieldAmbiguity() {
         assertThat(attribute.qualifier(), is("test"));
         assertThat(attribute.name(), is("test.test"));
     }
-}
\ No newline at end of file
+}
diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumnsTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumnsTests.java
index 0b82530022386..dd4f33311b42c 100644
--- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumnsTests.java
+++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysColumnsTests.java
@@ -17,7 +17,7 @@ public class SysColumnsTests extends ESTestCase {
     public void testSysColumns() {
         List<List<?>> rows = new ArrayList<>();
         SysColumns.fillInRows("test", "index", TypesTests.loadMapping("mapping-multi-field-variation.json", true), null, rows, null);
-        assertEquals(16, rows.size());
+        assertEquals(18, rows.size());
         assertEquals(24, rows.get(0).size());
 
         List<?> row = rows.get(0);
@@ -45,13 +45,21 @@ public void testSysColumns() {
         assertEquals(24, precision(row));
         assertEquals(8, bufferLength(row));
 
+        row = rows.get(6);
+        assertEquals("point", name(row));
+        assertEquals(Types.OTHER, sqlType(row));
+
         row = rows.get(7);
+        assertEquals("shape", name(row));
+        assertEquals(Types.OTHER, sqlType(row));
+
+        row = rows.get(9);
         assertEquals("some.dotted", name(row));
         assertEquals(Types.STRUCT, sqlType(row));
         assertEquals(null, radix(row));
         assertEquals(-1, bufferLength(row));
 
-        row = rows.get(15);
+        row = rows.get(17);
         assertEquals("some.ambiguous.normalized", name(row));
         assertEquals(Types.VARCHAR, sqlType(row));
         assertEquals(null, radix(row));
diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java
index 4423887c16135..120cea0c7894d 100644
--- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java
+++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java
@@ -34,6 +34,7 @@
 import java.util.TimeZone;
 
 import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.startsWith;
 
 public class QueryTranslatorTests extends ESTestCase {
@@ -261,4 +262,56 @@ public void testTranslateInExpression_HavingClause_PainlessAndNullHandling() {
         assertThat(aggFilter.scriptTemplate().params().toString(), startsWith("[{a=MAX(int){a->"));
         assertThat(aggFilter.scriptTemplate().params().toString(), endsWith(", {v=[10, null, 20, 30]}]"));
     }
+
+    public void testTranslateStAsWktForPoints() {
+        LogicalPlan p = plan("SELECT ST_AsWKT(point), ST_AsWKT(shape) FROM test " +
+            "WHERE ST_AsWKT(point) = 'point (10 20)'");
+        assertThat(p, instanceOf(Project.class));
+        assertThat(p.children().get(0), instanceOf(Filter.class));
+        Expression condition = ((Filter) p.children().get(0)).condition();
+        assertFalse(condition.foldable());
+        QueryTranslation translation = QueryTranslator.toQuery(condition, true);
+        assertNull(translation.query);
+        AggFilter aggFilter = translation.aggFilter;
+        assertEquals("InternalSqlScriptUtils.nullSafeFilter(InternalSqlScriptUtils.eq(" +
+                "InternalSqlScriptUtils.aswktPoint(InternalSqlScriptUtils.docValue(doc,params.v0))," +
+                "params.v1)" +
+                ")",
+            aggFilter.scriptTemplate().toString());
+        assertEquals("[{v=point}, {v=point (10 20)}]", aggFilter.scriptTemplate().params().toString());
+    }
+
+    public void testTranslateStAsWktForShapes() {
+        LogicalPlan p = plan("SELECT ST_AsWKT(point), ST_AsWKT(shape) FROM test " +
+            "WHERE ST_AsWKT(shape) = 'point (10 20)'");
+        assertThat(p, instanceOf(Project.class));
+        assertThat(p.children().get(0), instanceOf(Filter.class));
+        Expression condition = ((Filter) p.children().get(0)).condition();
+        assertFalse(condition.foldable());
+        QueryTranslation translation = QueryTranslator.toQuery(condition, true);
+        assertNull(translation.query);
+        AggFilter aggFilter = translation.aggFilter;
+        assertEquals("InternalSqlScriptUtils.nullSafeFilter(InternalSqlScriptUtils.eq(" +
+                "InternalSqlScriptUtils.aswktShape(InternalSqlScriptUtils.docValue(doc,params.v0))," +
+                "params.v1)" +
+                ")",
+            aggFilter.scriptTemplate().toString());
+        assertEquals("[{v=shape}, {v=point (10 20)}]", aggFilter.scriptTemplate().params().toString());
+    }
+
+    public void testTranslateStWktToSql() {
+        LogicalPlan p = plan("SELECT shape FROM test WHERE ST_WKTToSQL(keyword) = ST_WKTToSQL('point (10 20)')");
+        assertThat(p, instanceOf(Project.class));
+        assertThat(p.children().get(0), instanceOf(Filter.class));
+        Expression condition = ((Filter) p.children().get(0)).condition();
+        assertFalse(condition.foldable());
+        QueryTranslation translation = QueryTranslator.toQuery(condition, true);
+        assertNull(translation.query);
+        AggFilter aggFilter = translation.aggFilter;
+        assertEquals("InternalSqlScriptUtils.nullSafeFilter(" +
+                "InternalSqlScriptUtils.eq(InternalSqlScriptUtils.wktToSql(" +
+                "InternalSqlScriptUtils.docValue(doc,params.v0)),params.v1))",
+            aggFilter.scriptTemplate().toString());
+        assertEquals("[{v=keyword}, {v=point (10.0 20.0)}]", aggFilter.scriptTemplate().params().toString());
+    }
 }
diff --git a/x-pack/plugin/sql/src/test/resources/mapping-multi-field-variation.json b/x-pack/plugin/sql/src/test/resources/mapping-multi-field-variation.json
index 13c9f62b2136e..adc380580ceea 100644
--- a/x-pack/plugin/sql/src/test/resources/mapping-multi-field-variation.json
+++ b/x-pack/plugin/sql/src/test/resources/mapping-multi-field-variation.json
@@ -6,6 +6,8 @@
         "keyword" : { "type" : "keyword" },
         "date" :  { "type" : "date" },
         "unsupported" : { "type" : "ip_range" },
+        "point": {"type" : "geo_point"},
+        "shape": {"type" : "geo_shape"},
         "some" : {
             "properties" : {
                 "dotted" : {