فهرست منبع

SQL: Import Tableau connector (#63751)

* Import Tableau connector

Initial Tableau connector import.
Bogdan Pintea 5 سال پیش
والد
کامیت
f06ca33c07

+ 19 - 0
x-pack/plugin/sql/connectors/tableau/README.md

@@ -0,0 +1,19 @@
+# Tableau connector for Elasticsearch
+
+The Tableau Connector works in tandem with the Elastic JDBC driver to facilitate the query of Elasticsearch. It gives users a simple way to query Elasticsearch data from Tableau.
+After providing basic connection and authentication information, users can easily select Elasticsearch indices for use in Tableau Desktop and Tableau Server.
+
+## Installation
+
+1. Tableau connector for Elasticsearch installation:
+ - Go to the [Connector Download](https://www.elastic.co/downloads/tableau-connector) page.
+ - Download the _.taco_ connector file.
+ - Move the _.taco_ file here:
+    - Windows: C:\Users\[Windows User]\Documents\My Tableau Repository\Connectors
+    -  macOS: /Users/[user]/Documents/My Tableau Repository/Connectors
+2. Elasticsearch JDBC Driver Installation:
+ - Go to the [Driver Download](https://www.elastic.co/downloads/jdbc-client) page.
+ - Download the Elasticsearch JDBC Driver _.jar_ file and move it into the following directory:
+    - Windows - C:\Program Files\Tableau\Drivers
+    - macOS - /Users/[user]/Library/Tableau/Drivers
+3. Relaunch Tableau and connect with _Elasticsearch by Elastic_.

+ 21 - 0
x-pack/plugin/sql/connectors/tableau/connector/LICENSE.txt

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Tableau
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 11 - 0
x-pack/plugin/sql/connectors/tableau/connector/connection-dialog.tcd

@@ -0,0 +1,11 @@
+<connection-dialog class='elasticsearch-jdbc'>
+  <connection-config>
+    <authentication-mode value='Basic' />
+    <authentication-options>
+      <option name="UsernameAndPassword" default="true" />
+    </authentication-options>
+    <port-prompt value="Port: " default="9200" />
+    <show-ssl-checkbox value="true" />
+    <warehouse-prompt value="Additional settings" optional="true" />
+  </connection-config>
+</connection-dialog>

+ 40 - 0
x-pack/plugin/sql/connectors/tableau/connector/connectionBuilder.js

@@ -0,0 +1,40 @@
+(function dsbuilder(attr) {
+    var urlBuilder = "jdbc:es://";
+
+    if (attr["sslmode"] == "require") {
+        urlBuilder += "https://";
+    } else{
+        urlBuilder += "http://";
+    }
+    urlBuilder += attr["server"] + ":" + attr["port"];
+
+    var params = [];
+    params["user"] = attr["username"];
+    params["password"] = attr["password"];
+
+    var formattedParams = [];
+
+    for (var key in params) {
+        if (params[key]) {
+            var param = encodeURIComponent(params[key]);
+            formattedParams.push(connectionHelper.formatKeyValuePair(key, param));
+        }
+    }
+
+    if (formattedParams.length > 0) {
+        urlBuilder += "?" + formattedParams.join("&")
+    }
+
+    // logging visible in log.txt if -DLogLevel=Debug is added in Tableau command line
+    logging.log("ES JDBC URL before adding additional parameters: " + urlBuilder);
+
+    // TODO: wrap error-prone "free form"
+    var additionalConnectionParameters = attr[connectionHelper.attributeWarehouse];
+    if (additionalConnectionParameters != null && additionalConnectionParameters.trim().length > 0) {
+        urlBuilder += (formattedParams.length == 0) ? "?" : "&";
+        urlBuilder += additionalConnectionParameters;
+    }
+
+    logging.log("ES JDBC final URL: " + urlBuilder);
+    return [urlBuilder];
+})

+ 21 - 0
x-pack/plugin/sql/connectors/tableau/connector/connectionResolver.tdr

@@ -0,0 +1,21 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<tdr class='elasticsearch-jdbc'>
+    <connection-resolver>
+    <connection-builder>
+      <script file='connectionBuilder.js'/>
+    </connection-builder>
+    <connection-normalizer>
+      <required-attributes>
+        <attribute-list>
+          <attr>class</attr>
+          <attr>server</attr>
+          <attr>port</attr>
+          <attr>username</attr>
+          <attr>password</attr>
+          <attr>sslmode</attr>
+          <attr>warehouse</attr>
+        </attribute-list>
+      </required-attributes>
+    </connection-normalizer>
+    </connection-resolver>
+</tdr>

+ 1380 - 0
x-pack/plugin/sql/connectors/tableau/connector/dialect.tdd

@@ -0,0 +1,1380 @@
+<?xml version="1.0" encoding="utf-8"?>
+<dialect name='Elasticsearch'
+         class='elasticsearch-jdbc'
+         version='18.1'
+         base='PostgreSQL90Dialect'>
+   <function-map>
+    <function group='numeric' name='ABS' return-type='real'>
+      <formula>ABS(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='ABS' return-type='int'>
+      <formula>ABS(%1)</formula>
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='ACOS' return-type='real'>
+      <formula>ACOS(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='ASIN' return-type='real'>
+      <formula>ASIN(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='ATAN' return-type='real'>
+      <formula>ATAN(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='ATAN2' return-type='real'>
+      <formula>ATAN2(%1,%2)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='CEILING' return-type='real'>
+      <formula>CEILING(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='CEILING' return-type='int'>
+      <formula>CAST(CEIL(%1) AS BIGINT)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='CEILING' return-type='int'>
+      <formula>CAST(CEIL(%1) AS BIGINT)</formula>
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='COS' return-type='real'>
+      <formula>COS(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='COT' return-type='real'>
+      <formula>(CASE WHEN %1 != 0 THEN {fn COT(%1)} ELSE NULL END)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='DAY' return-type='int'>
+      <formula>DAY(%1)</formula>
+      <argument type='date' />
+    </function>
+    <function group='numeric' name='DAY' return-type='int'>
+      <formula>DAY(%1)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='numeric' name='MONTH' return-type='int'>
+      <formula>MONTH(%1)</formula>
+      <argument type='date' />
+    </function>
+    <function group='numeric' name='MONTH' return-type='int'>
+      <formula>MONTH(%1)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='numeric' name='YEAR' return-type='int'>
+      <formula>YEAR(%1)</formula>
+      <argument type='date' />
+    </function>
+    <function group='numeric' name='YEAR' return-type='int'>
+      <formula>YEAR(%1)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='numeric' name='NOW' return-type='datetime'>
+      <formula>NOW()</formula>
+    </function>
+    <function group='numeric' name='TODAY' return-type='date'>
+      <formula>TODAY()</formula>
+    </function>
+    <function group='numeric' name='DEGREES' return-type='real'>
+      <formula>DEGREES(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='EXP' return-type='real'>
+      <formula>EXP(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='FLOOR' return-type='real'>
+      <formula>FLOOR(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='FLOOR' return-type='int'>
+      <formula>CAST(FLOOR(%1) AS BIGINT)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='FLOOR' return-type='int'>
+      <formula>CAST(FLOOR(%1) AS BIGINT)</formula>
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='HEXBINX' return-type='real'>
+      <formula>(((CASE WHEN (ABS((%2) - (CAST(((%2) / SQRT(3.0)) AS LONG) * SQRT(3.0)))) + SQRT(3.0) * ((ABS((%1) - (CAST(((%1) / 3.0) AS LONG) * 3.0))) - 1.0) &gt; 0.0 THEN 1.5 ELSE 0.0 END) - (CASE WHEN ((%1) - (CAST( ( (%1) / 3.0 ) AS LONG) * 3.0) &lt; 0.0) AND ((CASE WHEN (ABS((%2) - (CAST( ( (%2) / SQRT(3.0) ) AS LONG) * SQRT(3.0)))) + SQRT(3.0) * ((ABS((%1) - (CAST( ( (%1) / 3.0 ) AS LONG) * 3.0))) - 1.0) &gt; 0.0 THEN 1.5 ELSE 0.0 END) &gt; 0.0) THEN 3.0 ELSE 0.0 END)) + (CAST( ( (%1) / 3.0 ) AS LONG) * 3.0))</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='HEXBINY' return-type='real'>
+      <formula>ROUND((((CASE WHEN (ABS((%2) - (ROUND(((%2) / SQRT(3.0)), 0) * SQRT(3.0)))) + SQRT(3.0) * ((ABS((%1) - (ROUND(((%1) / 3.0), 0) * 3.0))) - 1.0) &gt; 0.0 THEN SQRT(3.0) / 2.0 ELSE 0.0 END) - (CASE WHEN ((%2) - (ROUND(((%2) / SQRT(3.0)), 0 ) * SQRT(3.0)) &lt; 0.0) AND ((CASE WHEN (ABS((%2) - (ROUND(((%2) / SQRT(3.0)), 0) * SQRT(3.0)))) + SQRT(3.0) * ((ABS((%1) - (ROUND(((%1) / 3.0), 0 ) * 3.0))) - 1.0) &gt; 0.0 THEN SQRT(3.0) / 2.0 ELSE 0.0 END) &gt; 0.0) THEN SQRT(3.0) ELSE 0.0 END)) + (ROUND(((%2) / SQRT(3.0)), 0) * SQRT(3.0))), 3)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='LN' return-type='real'>
+      <formula>(CASE WHEN %1 > 0 THEN {fn LOG(%1)} ELSE NULL END)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='LOG' return-type='real'>
+      <formula>(CASE WHEN %1 > 0 THEN {fn LOG10(%1)} ELSE NULL END)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='LOG' return-type='real'>
+      <formula>(CASE WHEN %1 > 0 THEN {fn LOG10(%1)} / {fn LOG10(2)} ELSE NULL END)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='MOD' return-type='int'>
+      <formula>%1 % %2</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='PI' return-type='real'>
+      <formula>PI()</formula>
+    </function>
+    <function group='numeric' name='POWER' return-type='real'>
+      <formula>(CASE WHEN %1 &gt;= 0 OR FLOOR(%2) = %2 THEN POWER(%1,%2) END)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='POWER' return-type='real'>
+      <formula>POWER(%1,%2)</formula>
+      <argument type='real' />
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='POWER' return-type='real'>
+      <formula>POWER(CAST(%1 AS FLOAT),%2)</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='RADIANS' return-type='real'>
+      <formula>RADIANS(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='ROUND' return-type='real'>
+      <formula>ROUND(%1,0)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='ROUND' return-type='real'>
+      <formula>ROUND(%1,%2)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='ROUND' return-type='real'>
+      <formula>ROUND(%1,%2)</formula>
+      <argument type='real' />
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='ROUND' return-type='int'>
+      <formula>ROUND(%1,0)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='SIGN' return-type='int'>
+      <formula>SIGN(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='SIN' return-type='real'>
+      <formula>SIN(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='SQRT' return-type='real'>
+      <formula>(CASE WHEN %1 &lt; 0 THEN NULL ELSE SQRT(%1) END)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='SQUARE' return-type='real'>
+      <formula>POWER(%1,2)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='SQUARE' return-type='int'>
+      <formula>POWER(%1, 2)</formula>
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='TAN' return-type='real'>
+      <formula>TAN(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='TRUNC' return-type='real'>
+      <formula>TRUNCATE(%1)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric;logical' name='ZN' return-type='real'>
+      <formula>COALESCE(%1, 0)</formula>
+      <argument type='real' />
+    </function>
+    <function group='numeric;logical' name='ZN' return-type='int'>
+      <formula>IFNULL(%1, 0)</formula>
+      <argument type='int' />
+    </function>
+
+    <function group='aggregate' name='AVG' return-type='real'>
+      <formula>AVG(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='AVG' return-type='real'>
+      <formula>AVG(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='int' />
+    </function>
+
+    <function group='aggregate' name='COUNT' return-type='int'>
+      <formula>COUNT(%1)</formula>
+      <unagg-formula>(CASE WHEN %1 THEN 1 WHEN NOT %1 THEN 1 ELSE 0 END)</unagg-formula>
+      <argument type='bool' />
+    </function>
+    <function group='aggregate' name='COUNT' return-type='int'>
+      <formula>COUNT(%1)</formula>
+      <unagg-formula>(CASE WHEN (%1 IS NULL) THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='COUNT' return-type='int'>
+      <formula>COUNT(%1)</formula>
+      <unagg-formula>(CASE WHEN (%1 IS NULL) THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='str' />
+    </function>
+    <function group='aggregate' name='COUNT' return-type='int'>
+      <formula>COUNT(%1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='datetime' />
+    </function>
+    <function group='aggregate' name='COUNTD' return-type='int'>
+      <formula>COUNT(DISTINCT %1)</formula>
+      <unagg-formula>(CASE WHEN %1 THEN 1 WHEN NOT %1 THEN 1 ELSE 0 END)</unagg-formula>
+      <argument type='bool' />
+    </function>
+    <function group='aggregate' name='COUNTD' return-type='int'>
+      <formula>COUNT(DISTINCT %1)</formula>
+      <unagg-formula>(CASE WHEN (%1 IS NULL) THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='COUNTD' return-type='int'>
+      <formula>COUNT(DISTINCT %1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='int' />
+    </function>
+    <function group='aggregate' name='COUNTD' return-type='int'>
+      <formula>COUNT(DISTINCT %1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='str' />
+    </function>
+    <function group='aggregate' name='COUNTD' return-type='int'>
+      <formula>COUNT(DISTINCT %1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='datetime' />
+    </function>
+    <function group='aggregate' name='COUNTD' return-type='int'>
+      <formula>COUNT(DISTINCT %1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN 0 ELSE 1 END)</unagg-formula>
+      <argument type='date' />
+    </function>
+    <function group='aggregate' name='MAX' return-type='str'>
+      <formula>MAX(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='str' />
+    </function>
+    <function group='aggregate' name='MAX' return-type='bool'>
+      <formula>MAX(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='bool' />
+    </function>
+    <function group='aggregate' name='MAX' return-type='real'>
+      <formula>MAX(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='MAX' return-type='int'>
+      <formula>MAX(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='int' />
+    </function>
+    <function group='aggregate' name='MAX' return-type='datetime'>
+      <formula>MAX(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='datetime' />
+    </function>
+    <function group='aggregate' name='MAX' return-type='date'>
+      <formula>MAX(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='date' />
+    </function>
+    <function group='aggregate' name='MIN' return-type='str'>
+      <formula>MIN(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='str' />
+    </function>
+    <function group='aggregate' name='MIN' return-type='bool'>
+      <formula>(MIN(CASE WHEN %1 THEN 1 WHEN NOT %1 THEN 0 ELSE CAST(NULL AS INTEGER) END)=1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='bool' />
+    </function>
+    <function group='aggregate' name='MIN' return-type='real'>
+      <formula>MIN(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='MIN' return-type='int'>
+      <formula>MIN(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='int' />
+    </function>
+    <function group='aggregate' name='MIN' return-type='datetime'>
+      <formula>MIN(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='datetime' />
+    </function>
+    <function group='aggregate' name='MIN' return-type='date'>
+      <formula>MIN(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='date' />
+    </function>
+    <function group='numeric' name='MAX' return-type='real'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &gt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='MAX' return-type='int'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &gt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='MAX' return-type='datetime'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &gt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </function>
+    <function group='numeric' name='MAX' return-type='date'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &gt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+    <function group='numeric' name='MAX' return-type='str'>
+      <formula>(CASE WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL WHEN %1 &gt; %2 THEN %1 ELSE %2 END)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='numeric' name='MIN' return-type='real'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &lt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='numeric' name='MIN' return-type='int'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &lt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='numeric' name='MIN' return-type='str'>
+      <formula>(CASE WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL WHEN %1 &lt; %2 THEN %1 ELSE %2 END)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='numeric' name='MIN' return-type='datetime'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &lt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </function>
+    <function group='numeric' name='MIN' return-type='date'>
+      <formula>(CASE&#10;&#9;WHEN (%1 IS NULL) OR (%2 IS NULL) THEN NULL&#10;&#9;WHEN %1 &lt; %2 THEN %1&#10;&#9;ELSE %2 END)</formula>
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+    <function group='aggregate' name='STDEV' return-type='real'>
+      <formula>STDDEV_SAMP(%1)</formula>
+      <unagg-formula>NULL</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='STDEVP' return-type='real'>
+      <formula>STDDEV_POP(%1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN CAST(NULL AS DOUBLE) ELSE 0.0 END)</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='SUM' return-type='real'>
+      <formula>SUM(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='SUM' return-type='int'>
+      <formula>SUM(%1)</formula>
+      <unagg-formula>%1</unagg-formula>
+      <argument type='int' />
+    </function>
+    <function group='aggregate' name='VAR' return-type='real'>
+      <formula>VAR_SAMP(%1)</formula>
+      <unagg-formula>NULL</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='aggregate' name='VARP' return-type='real'>
+      <formula>VAR_POP(%1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN CAST(NULL AS DOUBLE) ELSE 0.0 END)</unagg-formula>
+      <argument type='real' />
+    </function>
+
+    <function group='cast' name='DATE' return-type='date'>
+      <formula>(CASE WHEN (%1 IS NULL) THEN CAST(NULL AS DATE) ELSE DATE_TRUNC(&apos;day&apos;, CAST(&apos;1900-01-01&apos; AS DATE) + FLOOR(%1) * INTERVAL 1 DAY) END)</formula>
+      <argument type='real' />
+    </function>
+    <function group='cast' name='DATE' return-type='date'>
+      <formula>(CASE WHEN (%1 IS NULL) THEN CAST(NULL AS DATE) ELSE (CAST(&apos;1900-01-01&apos; AS DATE) + %1 * INTERVAL 1 DAY) END)</formula>
+      <argument type='int' />
+    </function>
+
+    <function group='cast' name='DATE' return-type='date'>
+      <formula>CAST(%1 AS DATE)</formula>
+      <argument type='str' />
+    </function>
+    <function group='cast' name='DATE' return-type='date'>
+      <formula>CAST(%1 AS DATE)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='cast' name='DATE' return-type='date'>
+      <formula>CAST(%1 AS DATE)</formula>
+      <argument type='date' />
+    </function>
+    <function group='cast' name='DATETIME' return-type='datetime'>
+      <formula>CAST(%1 AS TIMESTAMP)</formula>
+      <argument type='real' />
+    </function>
+    <function group='cast' name='DATETIME' return-type='datetime'>
+      <formula>CAST(%1 AS TIMESTAMP)</formula>
+      <argument type='int' />
+    </function>
+    <function group='cast' name='DATETIME' return-type='datetime'>
+      <formula>CAST(%1 AS TIMESTAMP)</formula>
+      <argument type='str' />
+    </function>
+    <function group='cast' name='DATETIME' return-type='datetime'>
+      <formula>CAST(%1 as TIMESTAMP)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='cast' name='DATETIME' return-type='datetime'>
+      <formula>CAST(%1 AS TIMESTAMP)</formula>
+      <argument type='date' />
+    </function>
+    <function group='cast' name='FLOAT' return-type='real'>
+      <formula>CAST(%1 AS FLOAT)</formula>
+      <argument type='bool' />
+    </function>
+    <function group='cast' name='FLOAT' return-type='real'>
+      <formula>CAST(%1 AS REAL)</formula>
+      <argument type='real' />
+    </function>
+    <function group='cast' name='FLOAT' return-type='real'>
+      <formula>CAST(%1 AS DOUBLE)</formula>
+      <argument type='int' />
+    </function>
+    <function group='cast' name='FLOAT' return-type='real'>
+      <formula>CAST(%1 AS REAL)</formula>
+      <argument type='str' />
+    </function>
+    <function group='cast' name='FLOAT' return-type='real'>
+      <formula>CAST(DATE_DIFF(&apos;DAY&apos;, CAST(&apos;1900-01-01&apos; AS DATE), %1) AS FLOAT)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='cast' name='FLOAT' return-type='real'>
+      <formula>CAST(DATE_DIFF(&apos;DAY&apos;, CAST(&apos;1900-01-01&apos; AS DATE), %1) AS FLOAT)</formula>
+      <argument type='date' />
+    </function>
+    <function group='cast' name='INT' return-type='int'>
+      <formula>CAST(%1 AS INTEGER)</formula>
+      <argument type='bool' />
+    </function>
+    <function group='cast' name='INT' return-type='int'>
+      <formula>CAST(TRUNCATE(%1) AS BIGINT)</formula>
+      <argument type='real' />
+    </function>
+    <function group='cast' name='INT' return-type='int'>
+      <formula>CAST(%1 AS INTEGER)</formula>
+      <argument type='int' />
+    </function>
+    <function group='cast' name='INT' return-type='int'>
+      <formula>CAST(TRUNCATE(CAST(%1 AS REAL)) AS INTEGER)</formula>
+      <argument type='str' />
+    </function>
+
+    <function group='cast' name='INT' return-type='int'>
+      <formula>CAST(DATE_DIFF(&apos;DAY&apos;, CAST(&apos;1900-01-01&apos; AS DATE), %1) AS INTEGER)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='cast' name='INT' return-type='int'>
+      <formula>CAST(DATE_DIFF(&apos;DAY&apos;, CAST(&apos;1900-01-01&apos; AS DATE), %1) AS INTEGER)</formula>
+      <argument type='date' />
+    </function>
+
+    <function group='cast' name='STR' return-type='str'>
+      <formula>(CASE&#10;&#9;WHEN %1 = TRUE THEN &apos;1&apos;&#10;&#9;WHEN NOT %1 = TRUE THEN &apos;0&apos;&#10;&#9;ELSE CAST(NULL AS STRING) END)</formula>
+      <argument type='bool' />
+    </function>
+    <function group='cast' name='STR' return-type='str'>
+      <formula>CAST(%1 AS STRING)</formula>
+      <argument type='str' />
+    </function>
+    <function group='cast' name='STR' return-type='str'>
+      <formula>CAST(%1 AS STRING)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='cast' name='STR' return-type='str'>
+      <formula>CAST(%1 AS STRING)</formula>
+      <argument type='date' />
+    </function>
+    <function group='cast' name='STR' return-type='str'>
+      <formula>CAST(%1 AS STRING)</formula>
+      <argument type='real' />
+    </function>
+    <function group='cast' name='STR' return-type='str'>
+      <formula>CAST(%1 AS STRING)</formula>
+      <argument type='int' />
+    </function>
+    <function group='string' name='ASCII' return-type='int'>
+      <formula>ASCII(%1)</formula>
+      <argument type='str' />
+    </function>
+    <function group='string' name='CHAR' return-type='str'>
+      <formula>CHAR(CAST(%1 AS INTEGER))</formula>
+      <argument type='real' />
+    </function>
+    <function group='string' name='CHAR' return-type='str'>
+      <formula>CHAR(%1)</formula>
+      <argument type='int' />
+    </function>
+    <function group='string' name='CONTAINS' return-type='bool'>
+      <formula>(LOCATE(%2,%1) > 0)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='string' name='ENDSWITH' return-type='bool'>
+      <formula>RIGHT(%1, CHAR_LENGTH(%2)) = %2</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='string' name='LEFT' return-type='str'>
+      <formula>CASE WHEN %2 &lt; 0 THEN NULL ELSE LEFT(%1, %2) END</formula>
+      <argument type='str' />
+      <argument type='real' />
+    </function>
+    <function group='string' name='LEFT' return-type='str'>
+      <formula>CASE WHEN %2 &lt; 0 THEN NULL ELSE LEFT(%1, %2) END</formula>
+      <argument type='str' />
+      <argument type='int' />
+    </function>
+    <function group='string' name='LEN' return-type='int'>
+      <formula>CHAR_LENGTH(%1)</formula>
+      <argument type='str' />
+    </function>
+    <function group='string' name='LOWER' return-type='str'>
+      <formula>LCASE(%1)</formula>
+      <argument type='str' />
+    </function>
+    <function group='string' name='LTRIM' return-type='str'>
+      <formula>LTRIM(%1)</formula>
+      <argument type='str' />
+    </function>
+    <function group='string' name='LTRIM_THIS' return-type='str'>
+      <formula>LTRIM(%1,%2)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+
+    <function group='string' name='FIND' return-type='int'>
+      <formula>LOCATE(%2, %1)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='string' name='FIND' return-type='int'>
+      <formula>(CASE WHEN (%3 IS NULL) THEN NULL WHEN %3 &lt; 1 THEN LOCATE(%2,%1,1) ELSE LOCATE(%2,%1,CONVERT(TRUNCATE(%3,0), SQL_BIGINT)) END)</formula>
+      <argument type='str' />
+      <argument type='str' />
+      <argument type='real' />
+    </function>
+    <function group='string' name='FIND' return-type='int'>
+      <formula>LOCATE(%2, %1, %3)</formula>
+      <argument type='str' />
+      <argument type='str' />
+      <argument type='int' />
+    </function>
+    <function group='string' name='MID' return-type='str'>
+      <formula>&#10;(CASE WHEN (%2 IS NULL) OR %2 &lt; 1 THEN NULL&#10;      ELSE SUBSTRING(%1, CAST(FLOOR(%2) AS INTEGER), CHAR_LENGTH(%1) - (CAST(FLOOR(%2) AS INTEGER)) + 1) END)</formula>
+      <argument type='str' />
+      <argument type='real' />
+    </function>
+    <function group='string' name='MID' return-type='str'>
+      <formula>&#10;(CASE WHEN %2 IS NULL THEN NULL ELSE SUBSTRING(%1, %2, CHAR_LENGTH(%1)) END)</formula>
+      <argument type='str' />
+      <argument type='int' />
+    </function>
+    <function group='string' name='MID' return-type='str'>
+      <formula>(CASE WHEN %2 IS NULL OR %3 IS NULL THEN NULL&#10;      WHEN CAST(FLOOR(%3) AS INTEGER) &lt; 1 THEN &apos;&apos;&#10;      WHEN CAST(FLOOR(%2) AS INTEGER) &lt; 1 THEN SUBSTRING(%1, 1, CAST(FLOOR(%3) AS INTEGER))&#10;      ELSE SUBSTRING(%1, CAST(FLOOR(%2) AS INTEGER), CAST(FLOOR(%3) AS INTEGER)) END)</formula>
+      <argument type='str' />
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='string' name='MID' return-type='str'>
+      <formula>&#10;(CASE WHEN (%2 IS NULL) OR (%3 IS NULL) THEN NULL&#10;      WHEN %3 &lt; 1 THEN &apos;&apos;&#10;      WHEN %2 &lt; 1 THEN SUBSTRING(%1,1,%3)&#10;      ELSE SUBSTRING(%1,%2,%3) END)</formula>
+      <argument type='str' />
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='string' name='REPLACE' return-type='str'>
+      <formula>REPLACE(%1,%2,%3)</formula>
+      <argument type='str' />
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='string' name='RTRIM' return-type='str'>
+      <formula>RTRIM(%1)</formula>
+      <argument type='str' />
+    </function>
+    <function group='string' name='SPACE' return-type='str'>
+      <formula>SPACE(CAST(%1 AS INTEGER))</formula>
+      <argument type='real' />
+    </function>
+    <function group='string' name='SPACE' return-type='str'>
+      <formula>SPACE(%1)</formula>
+      <argument type='int' />
+    </function>
+    <function group='string' name='STARTSWITH' return-type='bool'>
+      <formula>(CASE WHEN %2 IS NULL THEN NULL WHEN %2 IS NOT NULL THEN (LOCATE(%2, %1) = 1) END)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='string' name='UPPER' return-type='str'>
+      <formula>UCASE(%1)</formula>
+      <argument type='str' />
+    </function>
+    <function group='string' name='TRIM' return-type='str'>
+      <formula>LTRIM(RTRIM(%1))</formula>
+      <argument type='str' />
+    </function>
+    <function group='aggregate' name='VARP' return-type='real'>
+      <formula>VAR_POP(%1)</formula>
+      <unagg-formula>(CASE WHEN %1 IS NULL THEN NULL ELSE 0.0 END)</unagg-formula>
+      <argument type='real' />
+    </function>
+    <function group='string' name='RIGHT' return-type='str'>
+      <formula>(CASE WHEN %2 &gt;= 0 THEN RIGHT(%1,%2) ELSE NULL END)</formula>
+      <argument type='str' />
+      <argument type='real' />
+    </function>
+    <function group='string' name='RIGHT' return-type='str'>
+      <formula>CASE WHEN %2 &gt;= 0 THEN {fn RIGHT(%1,%2)} ELSE NULL END</formula>
+      <argument type='str' />
+      <argument type='int' />
+    </function>
+    <function group='logical' name='ISNULL' return-type='bool'>
+      <formula>(%1 IS NULL)</formula>
+      <argument type='bool' />
+    </function>
+    <function group='logical' name='ISNULL' return-type='bool'>
+      <formula>(%1 IS NULL)</formula>
+      <argument type='real' />
+    </function>
+    <function group='logical' name='ISNULL' return-type='bool'>
+      <formula>(%1 IS NULL)</formula>
+      <argument type='str' />
+    </function>
+    <function group='logical' name='ISNULL' return-type='bool'>
+      <formula>(%1 IS NULL)</formula>
+      <argument type='datetime' />
+    </function>
+    <function group='logical' name='ISNULL' return-type='bool'>
+      <formula>(%1 IS NULL)</formula>
+      <argument type='spatial' />
+    </function>
+    <function group='logical' name='IIF' return-type='bool'>
+      <formula>IIF(%1 IS NULL, NULL, (IIF(%1, %2, %3)))</formula>
+      <argument type='bool' />
+      <argument type='bool' />
+      <argument type='bool' />
+    </function>
+    <function group='logical' name='IIF' return-type='real'>
+      <formula>IIF(%1 IS NULL, NULL, (IIF(%1, %2, %3)))</formula>
+      <argument type='bool' />
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='logical' name='IIF' return-type='real'>
+      <formula>(CASE WHEN %1 THEN %2 WHEN NOT %1 THEN %3 ELSE %4 END)</formula>
+      <argument type='bool' />
+      <argument type='real' />
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='logical' name='IIF' return-type='int'>
+      <formula>IIF(%1 IS NULL, NULL, (IIF(%1, %2, %3)))</formula>
+      <argument type='bool' />
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='logical' name='IIF' return-type='int'>
+      <formula>(CASE WHEN %1 THEN %2 WHEN NOT %1 THEN %3 ELSE %4 END)</formula>
+      <argument type='bool' />
+      <argument type='int' />
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='logical' name='IIF' return-type='str'>
+      <formula>IIF(%1 IS NULL, NULL, (IIF(%1, %2, %3)))</formula>
+      <argument type='bool' />
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='logical' name='IIF' return-type='str'>
+      <formula>(CASE WHEN %1 THEN %2 WHEN NOT %1 THEN %3 ELSE %4 END)</formula>
+      <argument type='bool' />
+      <argument type='str' />
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='logical' name='IIF' return-type='datetime'>
+      <formula>IIF(%1 IS NULL, NULL, (IIF(%1, %2, %3)))</formula>
+      <argument type='bool' />
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </function>
+    <function group='logical' name='IIF' return-type='datetime'>
+      <formula>(CASE WHEN %1 THEN %2 WHEN NOT %1 THEN %3 ELSE %4 END)</formula>
+      <argument type='bool' />
+      <argument type='datetime' />
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </function>
+    <function group='logical' name='IIF' return-type='date'>
+      <formula>IIF(%1 IS NULL, NULL, (IIF(%1, %2, %3)))</formula>
+      <argument type='bool' />
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+    <function group='logical' name='IIF' return-type='date'>
+      <formula>(CASE WHEN %1 THEN %2 WHEN NOT %1 THEN %3 ELSE %4 END)</formula>
+      <argument type='bool' />
+      <argument type='date' />
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+    <function group='logical' name='IFNULL' return-type='bool'>
+      <formula>IFNULL(%1, %2)</formula>
+      <argument type='bool' />
+      <argument type='bool' />
+    </function>
+    <function group='logical' name='IFNULL' return-type='real'>
+      <formula>IFNULL(%1, %2)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='logical' name='IFNULL' return-type='int'>
+      <formula>IFNULL(%1, %2)</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <function group='logical' name='IFNULL' return-type='str'>
+      <formula>IFNULL(%1, %2)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='logical' name='IFNULL' return-type='datetime'>
+      <formula>IFNULL(%1, %2)</formula>
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </function>
+    <function group='logical' name='IFNULL' return-type='date'>
+      <formula>IFNULL(%1, %2)</formula>
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+    <function group='logical' name='ISDATE' return-type='bool'>
+      <formula>(CAST(%1 AS DATE) IS NOT NULL)</formula>
+      <argument type='str' />
+    </function>
+
+    <function group='operator' name='+' return-type='str'>
+      <formula>(CASE WHEN %1 IS NULL OR %2 IS NULL THEN NULL ELSE CONCAT(%1, %2) END)</formula>
+      <argument type='str' />
+      <argument type='str' />
+    </function>
+    <function group='operator' name='+' return-type='datetime'>
+      <formula>(CASE WHEN %2 IS NOT NULL THEN DATEADD( &apos;s&apos;, CAST((%2 * 24 * 60 - CAST(%2 * 24 * 60 AS INTEGER)) * 60 AS INTEGER), CAST(DATEADD(&apos;mi&apos;, CAST((%2 * 24 - CAST(%2 * 24 AS INTEGER)) * 60 AS INTEGER), CAST(DATEADD(&apos;hh&apos;, CAST((%2 - CAST(%2 AS INTEGER)) * 24 AS INTEGER), CAST(DATEADD(&apos;d&apos;, CAST(%2 AS INTEGER), CAST(%1 AS TIMESTAMP)) AS TIMESTAMP)) AS TIMESTAMP)) AS TIMESTAMP)) END)</formula>
+      <argument type='datetime' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='+' return-type='datetime'>
+      <formula>(CAST(%1 AS TIMESTAMP) + %2 * INTERVAL &apos;1&apos; DAY)</formula>
+      <argument type='datetime' />
+      <argument type='int' />
+    </function>
+    <function group='operator' name='+' return-type='datetime'>
+      <formula>(%1 + %2)</formula>
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </function>
+
+    <function group='operator' name='+' return-type='datetime'>
+      <formula>(CASE WHEN %2 IS NOT NULL THEN DATEADD( &apos;s&apos;, CAST((%2 * 24 * 60 - CAST(%2 * 24 * 60 AS INTEGER)) * 60 AS INTEGER), CAST(DATEADD(&apos;mi&apos;, CAST((%2 * 24 - CAST(%2 * 24 AS INTEGER)) * 60 AS INTEGER), CAST(DATEADD(&apos;hh&apos;, CAST((%2 - CAST(%2 AS INTEGER)) * 24 AS INTEGER), CAST(DATEADD(&apos;d&apos;, CAST(%2 AS INTEGER), CAST(%1 AS TIMESTAMP)) AS TIMESTAMP)) AS TIMESTAMP)) AS TIMESTAMP)) END)</formula>
+      <argument type='date' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='+' return-type='date'>
+      <formula>DATEADD(&apos;day&apos;, CAST(TRUNCATE(%2) AS INTEGER), %1)</formula>
+      <argument type='date' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='+' return-type='date'>
+      <formula>(%1 + %2 * INTERVAL &apos;1&apos; DAY)</formula>
+      <argument type='date' />
+      <argument type='int' />
+    </function>
+    <function group='operator' name='+' return-type='date'>
+      <formula>(%1 + %2)</formula>
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+
+    <function group='operator' name='%' return-type='real'>
+      <formula>(CASE WHEN %2 = 0 THEN NULL ELSE MOD(%1,%2))</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='%' return-type='int'>
+      <formula>(CASE WHEN %2 = 0 THEN NULL ELSE MOD(%1,%2) END)</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+
+    <function group='operator' name='-' return-type='int'>
+      <formula>(DATEDIFF(&apos;d&apos;,%2,%1))</formula>
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+    <function group='operator' name='-' return-type='real'>
+      <formula>(DATE_DIFF(&apos;DAY&apos;, CAST(%2 AS TIMESTAMP), CAST(%1 AS TIMESTAMP)) + (COALESCE(HOUR(%1), 0) - COALESCE(HOUR(%2), 0) + (COALESCE(MINUTE(%1), 0) - COALESCE(MINUTE(%2), 0) + (COALESCE(SECOND(%1), 0) - COALESCE(SECOND(%2), 0)) / 60.0) / 60.0) / 24.0)</formula>
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </function>
+    <function group='operator' name='-' return-type='real'>
+      <formula>CASE WHEN %1 IS NULL OR %2 IS NULL THEN CAST(NULL AS DOUBLE) ELSE ((CAST(CAST(%1 AS DATE) AS LONG) - CAST(%2 AS LONG)) / 86400000.0 + CAST(EXTRACT(HOUR FROM %1) AS DOUBLE) / 24 +  CAST(EXTRACT(MINUTE FROM %1) AS DOUBLE) / (24 * 60) + CAST(EXTRACT(SECOND FROM %1) AS DOUBLE) / (24 * 60 * 60) ) END</formula>
+      <argument type='datetime' />
+      <argument type='date' />
+    </function>
+    <function group='operator' name='-' return-type='real'>
+      <formula>(CAST(%1 AS LONG) - CAST(%2 AS LONG)) / 86400000.0</formula>
+      <argument type='date' />
+      <argument type='datetime' />
+    </function>
+
+    <function group='operator' name='-' return-type='real'>
+      <formula>(CAST(%1 AS LONG) - CAST(%2 AS LONG)) / 86400000.0</formula>
+      <argument type='date' />
+      <argument type='date' />
+    </function>
+
+    <function group='operator' name='-' return-type='datetime'>
+      <formula>(%1 - (CAST(%2 AS INTEGER) * INTERVAL 1 DAY) - (CAST((%2 - CAST(%2 AS INTEGER)) * 24 AS INTEGER) * INTERVAL 1 HOUR) - (CAST((%2 * 24  - CAST(%2 * 24 AS INTEGER)) * 60 AS INTEGER) * INTERVAL 1 MINUTE) - (CAST((%2 * 24 * 60  - CAST(%2 * 24 * 60 AS INTEGER)) * 60 AS INTEGER) * INTERVAL 1 SECOND))</formula>
+      <argument type='datetime' />
+      <argument type='real' />
+    </function>
+
+    <function group='operator' name='-' return-type='datetime'>
+      <formula>(CAST(%1 AS TIMESTAMP) - %2 * INTERVAL &apos;1&apos; DAY)</formula>
+      <argument type='datetime' />
+      <argument type='int' />
+    </function>
+    <function group='operator' name='-' return-type='datetime'>
+      <formula>DATEADD(&apos;second&apos;,CAST((%2 * 24 * 60 - CAST(%2 * 24 * 60 AS INTEGER)) * -60 AS INTEGER),DATEADD(&apos;minute&apos;,CAST((%2 * 24 - CAST(%2 * 24 AS INTEGER)) * -60 AS INTEGER),DATEADD(&apos;hour&apos;,CAST((%2 - CAST(%2 AS INTEGER)) * -24 AS INTEGER),DATEADD(&apos;day&apos;,CAST(-%2 AS INTEGER),CAST(%1 AS TIMESTAMP)))))</formula>
+      <argument type='date' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='-' return-type='date'>
+      <formula>DATEADD(&apos;day&apos;, CAST(TRUNCATE(-1 * %2) AS INTEGER), %1)</formula>
+      <argument type='date' />
+      <argument type='real' />
+    </function>
+
+    <function group='operator' name='-' return-type='date'>
+      <formula>DATEADD(&apos;day&apos;, -1 * %2, %1)</formula>
+      <argument type='date' />
+      <argument type='int' />
+    </function>
+
+    <function group='operator' name='/' return-type='real'>
+      <formula>(CASE WHEN %2 &lt;&gt; 0 THEN %1 / %2 END)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='/' return-type='real'>
+      <formula>(CASE WHEN %2 = 0 THEN NULL ELSE %1 / %2 END)</formula>
+      <argument type='real' />
+      <argument type='int' />
+    </function>
+    <function group='operator' name='/' return-type='real'>
+      <formula>(CASE WHEN %2 = 0 THEN NULL ELSE %1 / %2 END)</formula>
+      <argument type='int' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='/' return-type='real'>
+      <formula>(CASE WHEN %2 = 0 THEN CAST(NULL AS DOUBLE) ELSE CAST(%1 AS DOUBLE) / %2 END)</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+
+    <function group='operator' name='^^' return-type='real'>
+      <formula>(CASE WHEN %1 &lt; 0 AND TRUNCATE(%2) &lt;&gt; %2 THEN NULL ELSE POWER(%1,%2) END)</formula>
+      <argument type='real' />
+      <argument type='real' />
+    </function>
+    <function group='operator' name='^^' return-type='real'>
+      <formula>(CASE WHEN %1 &lt; 0 AND FLOOR(%2) &lt;&gt; %2 THEN NULL ELSE POWER(%1,%2) END)</formula>
+      <argument type='real' />
+      <argument type='int' />
+    </function>
+    <function group='operator' name='^^' return-type='real'>
+      <formula>POWER(CAST(%1 AS FLOAT),%2)</formula>
+      <argument type='int' />
+      <argument type='int' />
+    </function>
+    <date-function name='DATENAME' return-type='str'>
+      <formula part='year'>LTRIM(CAST(YEAR(%2) AS VARCHAR))</formula>
+      <formula part='quarter'>LTRIM(CAST(QUARTER(%2) AS VARCHAR))</formula>
+      <formula part='month'>MONTHNAME(%2)</formula>
+      <formula part='dayofyear'>LTRIM(CAST(DAYOFYEAR(%2) AS VARCHAR))</formula>
+      <formula part='day'>LTRIM(CAST(DAYOFMONTH(%2) AS VARCHAR))</formula>
+      <formula part='weekday'>DAYNAME(%2)</formula>
+      <formula part='week'>LTRIM(CAST(WEEK(%2) AS VARCHAR))</formula>
+      <formula part='hour'>LTRIM(CAST(HOUR(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='minute'>LTRIM(CAST(MINUTE(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='second'>LTRIM(CAST(SECOND(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+    </date-function>
+    <date-function name='DATENAME' return-type='str'>
+      <formula part='year'>LTRIM(CAST(YEAR(%2) AS VARCHAR))</formula>
+      <formula part='quarter'>LTRIM(CAST(QUARTER(%2) AS VARCHAR))</formula>
+      <formula part='month'>MONTHNAME(%2)</formula>
+      <formula part='dayofyear'>LTRIM(CAST(DAYOFYEAR(%2) AS VARCHAR))</formula>
+      <formula part='day'>LTRIM(CAST(DAYOFMONTH(%2) AS VARCHAR))</formula>
+      <formula part='weekday'>DAYNAME(%2)</formula>
+      <formula part='week'>LTRIM(CAST(WEEK(%2) AS VARCHAR))</formula>
+      <formula part='hour'>LTRIM(CAST(HOUR(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='minute'>LTRIM(CAST(MINUTE(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='second'>LTRIM(CAST(SECOND(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+    </date-function>
+
+    <date-function name='DATENAME' return-type='str'>
+      <formula part='year'>LTRIM(CAST(YEAR(%2) AS VARCHAR))</formula>
+      <formula part='quarter'>LTRIM(CAST(QUARTER(%2) AS VARCHAR))</formula>
+      <formula part='month'>MONTHNAME(%2)</formula>
+      <formula part='dayofyear'>LTRIM(CAST(DAYOFYEAR(%2) AS VARCHAR))</formula>
+      <formula part='day'>LTRIM(CAST(DAYOFMONTH(%2) AS VARCHAR))</formula>
+      <formula part='weekday'>DAYNAME(%2)</formula>
+      <formula part='week'>RTRIM(CAST(CAST(FLOOR((7 + DAYOFYEAR(%2) - 1 + ISODOW(CAST(CONCAT(RIGHT(CAST(CAST(ABS(YEAR(%2)) AS LONG) AS STRING),4), &apos;-01-01&apos;) AS DATE)) - 1) / 7) AS LONG) AS STRING))</formula>
+      <formula part='hour'>LTRIM(CAST(HOUR(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='minute'>LTRIM(CAST(MINUTE(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='second'>LTRIM(CAST(SECOND(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+      <argument type='localstr' />
+    </date-function>
+    <date-function name='DATENAME' return-type='str'>
+      <formula part='year'>LTRIM(CAST(YEAR(%2) AS VARCHAR))</formula>
+      <formula part='quarter'>LTRIM(CAST(QUARTER(%2) AS VARCHAR))</formula>
+      <formula part='month'>MONTHNAME(%2)</formula>
+      <formula part='dayofyear'>LTRIM(CAST(DAYOFYEAR(%2) AS VARCHAR))</formula>
+      <formula part='day'>LTRIM(CAST(DAYOFMONTH(%2) AS VARCHAR))</formula>
+      <formula part='weekday'>DAYNAME(%2)</formula>
+      <formula part='week'>RTRIM(CAST(CAST(FLOOR((7 + DAYOFYEAR(%2) - 1 + ISODOW(CAST(CONCAT(RIGHT(CAST(CAST(ABS(YEAR(%2)) AS LONG) AS STRING),4), &apos;-01-01&apos;) AS DATE)) - 1) / 7) AS LONG) AS STRING))</formula>
+      <formula part='hour'>LTRIM(CAST(HOUR(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='minute'>LTRIM(CAST(MINUTE(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <formula part='second'>LTRIM(CAST(SECOND(CAST(%2 AS TIMESTAMP)) AS VARCHAR))</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+      <argument type='localstr' />
+    </date-function>
+
+    <date-function name='DATEPART' return-type='int'>
+      <formula>DATE_PART(&apos;%1&apos;,%2)</formula>
+      <formula part='year'>DATE_PART(&apos;year&apos;,%2)</formula>
+      <formula part='quarter'>DATE_PART(&apos;quarter&apos;,%2)</formula>
+      <formula part='month'>DATE_PART(&apos;month&apos;,%2)</formula>
+      <formula part='dayofyear'>DATE_PART(&apos;dayofyear&apos;,%2)</formula>
+      <formula part='day'>DATE_PART(&apos;day&apos;,%2)</formula>
+      <formula part='weekday'>DATE_PART(&apos;weekday&apos;,%2)</formula>
+      <formula part='week'>DATE_PART(&apos;week&apos;,%2)</formula>
+      <formula part='hour'>DATE_PART(&apos;hour&apos;,%2)</formula>
+      <formula part='minute'>DATE_PART(&apos;minute&apos;,%2)</formula>
+      <formula part='second'>DATE_PART(&apos;second&apos;,%2)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+    </date-function>
+    <date-function name='DATEPART' return-type='int'>
+      <formula>DATE_PART(&apos;%1&apos;,%2)</formula>
+      <formula part='year'>DATE_PART(&apos;year&apos;,%2)</formula>
+      <formula part='quarter'>DATE_PART(&apos;quarter&apos;,%2)</formula>
+      <formula part='month'>DATE_PART(&apos;month&apos;,%2)</formula>
+      <formula part='dayofyear'>DATE_PART(&apos;dayofyear&apos;,%2)</formula>
+      <formula part='day'>DATE_PART(&apos;day&apos;,%2)</formula>
+      <formula part='weekday'>DATE_PART(&apos;weekday&apos;,%2)</formula>
+      <formula part='week'>DATE_PART(&apos;week&apos;,%2)</formula>
+      <formula part='hour'>DATE_PART(&apos;hour&apos;,%2)</formula>
+      <formula part='minute'>DATE_PART(&apos;minute&apos;,%2)</formula>
+      <formula part='second'>DATE_PART(&apos;second&apos;,%2)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+    </date-function>
+    <date-function name='DATEPART' return-type='int'>
+      <formula>DATE_PART(&apos;%1&apos;,%2)</formula>
+      <formula part='year'>DATE_PART(&apos;year&apos;,%2)</formula>
+      <formula part='quarter'>DATE_PART(&apos;quarter&apos;,%2)</formula>
+      <formula part='month'>DATE_PART(&apos;month&apos;,%2)</formula>
+      <formula part='dayofyear'>DATE_PART(&apos;dayofyear&apos;,%2)</formula>
+      <formula part='day'>DATE_PART(&apos;day&apos;,%2)</formula>
+      <formula part='weekday'>DATE_PART(&apos;weekday&apos;,%2)</formula>
+      <!--<formula part='week'>IIF(%3=1, ISO_WEEK_OF_YEAR(%2), DATE_PART(&apos;week&apos;,%2))</formula>-->
+      <!--<formula part='week'>(5 + DAY_OF_YEAR(%2) + DAY_OF_WEEK(DATE_TRUNC(&apos;year&apos;, %2)) / 7</formula>-->
+      <formula part='week'>FLOOR((7 + DAY_OF_YEAR(%2) - 1 + ((((CAST(DATE_TRUNC(&apos;year&apos;, CAST(%2 AS DATE)) AS LONG) / 86400000) + 2440587.5 + 1) % 7))) / 7)</formula>
+      <formula part='hour'>DATE_PART(&apos;hour&apos;,%2)</formula>
+      <formula part='minute'>DATE_PART(&apos;minute&apos;,%2)</formula>
+      <formula part='second'>DATE_PART(&apos;second&apos;,%2)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+      <argument type='localstr' />
+    </date-function>
+    <date-function name='DATEPART' return-type='int'>
+      <formula>DATE_PART(&apos;%1&apos;,%2)</formula>
+      <formula part='year'>DATE_PART(&apos;year&apos;,%2)</formula>
+      <formula part='quarter'>DATE_PART(&apos;quarter&apos;,%2)</formula>
+      <formula part='month'>DATE_PART(&apos;month&apos;,%2)</formula>
+      <formula part='dayofyear'>DATE_PART(&apos;dayofyear&apos;,%2)</formula>
+      <formula part='day'>DATE_PART(&apos;day&apos;,%2)</formula>
+      <formula part='weekday'>DATE_PART(&apos;weekday&apos;,%2)</formula>
+      <formula part='week'>FLOOR((7 + DAY_OF_YEAR(%2) - 1 + ((((CAST(DATE_TRUNC(&apos;year&apos;, CAST(%2 AS DATE)) AS LONG) / 86400000) + 2440587.5 + 1) % 7))) / 7)</formula>
+      <formula part='hour'>DATE_PART(&apos;hour&apos;,%2)</formula>
+      <formula part='minute'>DATE_PART(&apos;minute&apos;,%2)</formula>
+      <formula part='second'>DATE_PART(&apos;second&apos;,%2)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+      <argument type='localstr' />
+    </date-function>
+    <date-function name='DATETRUNC' return-type='datetime'>
+      <formula>DATE_TRUNC(&apos;%1&apos;,%2)</formula>
+      <formula part='year'>DATE_TRUNC(&apos;year&apos;,%2)</formula>
+      <formula part='quarter'>DATE_TRUNC(&apos;quarter&apos;,%2)</formula>
+      <formula part='month'>DATE_TRUNC(&apos;month&apos;,%2)</formula>
+      <formula part='dayofyear'>DATE_TRUNC(&apos;day&apos;,%2)</formula>
+      <formula part='day'>DATE_TRUNC(&apos;day&apos;,%2)</formula>
+      <formula part='weekday'>DATE_TRUNC(&apos;day&apos;,%2)</formula>
+      <formula part='week'>CAST(%2 AS DATE) + (-1 * (( 7 + DAYOFWEEK( CAST(%2 AS DATE) ) - 1 ) % 7)) * INTERVAL 1 DAY</formula>
+      <formula part='hour'>DATE_TRUNC(&apos;hour&apos;,%2)</formula>
+      <formula part='minute'>DATE_TRUNC(&apos;minute&apos;,%2)</formula>
+      <formula part='second'>DATE_TRUNC(&apos;second&apos;,%2)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+    </date-function>
+    <!-- to change CAST(DATE_TRUNC AS TIMESTAMP) into DATE_TRUNC(CAST %2 AS TIMESTAMP) after https://github.com/elastic/elasticsearch/issues/42041 is fixed -->
+    <date-function name='DATETRUNC' return-type='datetime'>
+      <formula>CAST(DATE_TRUNC(&apos;%1&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='year'>CAST(DATE_TRUNC(&apos;year&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='quarter'>CAST(DATE_TRUNC(&apos;quarter&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='month'>CAST(DATE_TRUNC(&apos;month&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='dayofyear'>CAST(DATE_TRUNC(&apos;day&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='day'>CAST(DATE_TRUNC(&apos;day&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='weekday'>CAST(DATE_TRUNC(&apos;day&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='week'>CAST(%2 AS DATE) + (-1 * (( 7 + DAYOFWEEK( CAST(%2 AS DATE) ) - 1 ) % 7)) * INTERVAL 1 DAY</formula>
+      <formula part='hour'>CAST(DATE_TRUNC(&apos;hour&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='minute'>CAST(DATE_TRUNC(&apos;minute&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='second'>CAST(DATE_TRUNC(&apos;second&apos;,%2) AS TIMESTAMP)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+    </date-function>
+    <date-function name='DATETRUNC' return-type='datetime'>
+      <formula>DATE_TRUNC(&apos;%1&apos;,%2)</formula>
+      <formula part='year'>DATE_TRUNC(&apos;year&apos;,%2)</formula>
+      <formula part='quarter'>DATE_TRUNC(&apos;quarter&apos;,%2)</formula>
+      <formula part='month'>DATE_TRUNC(&apos;month&apos;,%2)</formula>
+      <formula part='dayofyear'>DATE_TRUNC(&apos;day&apos;,%2)</formula>
+      <formula part='day'>DATE_TRUNC(&apos;day&apos;,%2)</formula>
+      <formula part='weekday'>(DATE_TRUNC(&apos;day&apos;, CAST(%2 AS DATE)) - (7 + (((CAST(DATE_TRUNC(&apos;year&apos;, CAST(%2 AS DATE)) AS LONG) / 86400000) + 2440587.5 + 1) % 7) - %3) % 7)</formula>
+      <formula part='week'>CAST(%2 AS DATE) + (-1 * (( 7 + DAYOFWEEK( CAST(%2 AS DATE) ) - 2 ) % 7)) * INTERVAL 1 DAY</formula>
+      <formula part='hour'>DATE_TRUNC(&apos;hour&apos;,%2)</formula>
+      <formula part='minute'>DATE_TRUNC(&apos;minute&apos;,%2)</formula>
+      <formula part='second'>DATE_TRUNC(&apos;second&apos;,%2)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+      <argument type='localstr' />
+    </date-function>
+    <date-function name='DATETRUNC' return-type='datetime'>
+      <formula>CAST(DATE_TRUNC(&apos;%1&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='year'>CAST(DATE_TRUNC(&apos;year&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='quarter'>CAST(DATE_TRUNC(&apos;quarter&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='month'>CAST(DATE_TRUNC(&apos;month&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='dayofyear'>CAST(DATE_TRUNC(&apos;day&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='day'>CAST(DATE_TRUNC(&apos;day&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='weekday'>CAST(DATE_TRUNC(&apos;day&apos;,%2) AS TIMESTAMP)</formula>
+      <!--<formula part='week'>(DATE_TRUNC(&apos;day&apos;, CAST(%2 AS DATE)) - (7 + (((CAST(DATE_TRUNC(&apos;year&apos;, CAST(%2 AS DATE)) AS LONG) / 86400000) + 2440587.5 + 1) % 7) - %3) % 7)</formula>-->
+      <!--<formula part='week'>CAST(DATE_TRUNC(&apos;wEEk&apos;,%2) AS TIMESTAMP)</formula>-->
+      <!--<formula part='week'>CAST(%2 AS DATE) + (-1 * (( 7 + DAYOFWEEK( CAST(%2 AS DATE) ) - 2 ) % 7)) * INTERVAL 1 DAY</formula>-->
+      <formula part='week'>CAST(%2 AS DATE) + (-1 * (( 7 + DAYOFWEEK( CAST(%2 AS DATE) ) - 2 ) % 7)) * INTERVAL 1 DAY</formula>
+      <formula part='hour'>CAST(DATE_TRUNC(&apos;hour&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='minute'>CAST(DATE_TRUNC(&apos;minute&apos;,%2) AS TIMESTAMP)</formula>
+      <formula part='second'>CAST(DATE_TRUNC(&apos;second&apos;,%2) AS TIMESTAMP)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+      <argument type='localstr' />
+    </date-function>
+
+    <!-- DATE_TRUNC was added and we don't need the formulas below. Keeping them for reference only -->
+    <!--
+    <date-function name='DATETRUNC' return-type='datetime'>
+      <formula part='year'>({fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)} + {fn CONVERT({fn TRUNCATE((-1 * ({fn DAYOFYEAR({fn CONVERT(%2, SQL_DATE)})} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' DAY)</formula>
+      <formula part='quarter'>(({fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)} + {fn CONVERT({fn TRUNCATE((-1 * ({fn DAYOFYEAR({fn CONVERT(%2, SQL_DATE)})} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' DAY) + {fn CONVERT({fn TRUNCATE((3 * ({fn CONVERT({fn TRUNCATE({fn QUARTER({fn CONVERT(%2, SQL_DATE)})},0)}, SQL_BIGINT)} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' MONTH)</formula>
+      <formula part='month'>({fn CONVERT(%2, SQL_DATE)} + {fn CONVERT({fn TRUNCATE((-1 * ({fn EXTRACT(DAY FROM %2)} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' DAY)</formula>
+      <formula part='dayofyear'>{fn CONVERT(%2, SQL_DATE)}</formula>
+      <formula part='day'>{fn CONVERT(%2, SQL_DATE)}</formula>
+      <formula part='weekday'>{fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)}</formula>
+      <formula part='week'>({fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)} + (-1 * ({fn MOD((7 + {fn DAYOFWEEK({fn CONVERT(%2, SQL_DATE)})} - 2), 7)})) * INTERVAL '1' DAY)</formula>
+      <formula part='hour'>({fn CONVERT(%2, SQL_DATE)} + {fn EXTRACT(HOUR FROM %2)} * INTERVAL '1' HOUR)</formula>
+      <formula part='minute'>(({fn CONVERT({fn CONVERT(%2, SQL_TIMESTAMP)}, SQL_DATE)} + {fn EXTRACT(HOUR FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' HOUR) + {fn EXTRACT(MINUTE FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' MINUTE)</formula>
+      <formula part='second'>((({fn CONVERT({fn CONVERT(%2, SQL_TIMESTAMP)}, SQL_DATE)} + {fn EXTRACT(HOUR FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' HOUR) + {fn EXTRACT(MINUTE FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' MINUTE) + {fn EXTRACT(SECOND FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' SECOND)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+    </date-function>
+    <date-function name='DATETRUNC' return-type='datetime'>
+      <formula part='year'>({fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)} + {fn CONVERT({fn TRUNCATE((-1 * ({fn DAYOFYEAR({fn CONVERT(%2, SQL_DATE)})} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' DAY)</formula>
+      <formula part='quarter'>(({fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)} + {fn CONVERT({fn TRUNCATE((-1 * ({fn DAYOFYEAR({fn CONVERT(%2, SQL_DATE)})} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' DAY) + {fn CONVERT({fn TRUNCATE((3 * ({fn CONVERT({fn TRUNCATE({fn QUARTER({fn CONVERT(%2, SQL_DATE)})},0)}, SQL_BIGINT)} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' MONTH)</formula>
+      <formula part='month'>({fn CONVERT(%2, SQL_DATE)} + {fn CONVERT({fn TRUNCATE((-1 * ({fn EXTRACT(DAY FROM %2)} - 1)),0)}, SQL_BIGINT)} * INTERVAL '1' DAY)</formula>
+      <formula part='dayofyear'>{fn CONVERT(%2, SQL_DATE)}</formula>
+      <formula part='day'>{fn CONVERT(%2, SQL_DATE)}</formula>
+      <formula part='weekday'>{fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)}</formula>
+      <formula part='week'>({fn CONVERT({fn CONVERT(%2, SQL_DATE)}, SQL_DATE)} + (-1 * ({fn MOD((7 + {fn DAYOFWEEK({fn CONVERT(%2, SQL_DATE)})} - 2), 7)})) * INTERVAL '1' DAY)</formula>
+      <formula part='hour'>({fn CONVERT(%2, SQL_DATE)} + {fn EXTRACT(HOUR FROM %2)} * INTERVAL '1' HOUR)</formula>
+      <formula part='minute'>(({fn CONVERT({fn CONVERT(%2, SQL_TIMESTAMP)}, SQL_DATE)} + {fn EXTRACT(HOUR FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' HOUR) + {fn EXTRACT(MINUTE FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' MINUTE)</formula>
+      <formula part='second'>((({fn CONVERT({fn CONVERT(%2, SQL_TIMESTAMP)}, SQL_DATE)} + {fn EXTRACT(HOUR FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' HOUR) + {fn EXTRACT(MINUTE FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' MINUTE) + {fn EXTRACT(SECOND FROM {fn CONVERT(%2, SQL_TIMESTAMP)})} * INTERVAL '1' SECOND)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+    </date-function>
+    -->
+    <date-function name='DATEADD' return-type='datetime'>
+      <formula>DATEADD(%1,%2,%3)</formula>
+      <formula part='year'>DATEADD(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEADD(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEADD(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEADD(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEADD(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEADD(&apos;dw&apos;,%2,%3)</formula>
+      <formula part='week'>DATEADD(&apos;ww&apos;,%2,%3)</formula>
+      <formula part='hour'>DATEADD(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEADD(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEADD(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='real' />
+      <argument type='datetime' />
+    </date-function>
+    <date-function name='DATEADD' return-type='datetime'>
+      <formula>DATEADD(%1,%2,%3)</formula>
+      <formula part='year'>DATEADD(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEADD(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEADD(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEADD(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEADD(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEADD(&apos;dw&apos;,%2,%3)</formula>
+      <formula part='week'>DATEADD(&apos;ww&apos;,%2,%3)</formula>
+      <formula part='hour'>DATEADD(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEADD(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEADD(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='int' />
+      <argument type='datetime' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <!--<formula part='week'>CAST((((FLOOR(CAST(%3 AS LONG) / 86400000) - DAYOFWEEK(%3) ) - (FLOOR(CAST(%2 AS LONG) / 86400000) - DAYOFWEEK(%2))) / 7) AS INTEGER)</formula>-->
+      <formula part='week'>DATEDIFF(&apos;ww&apos;,%2,%3)</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+      <argument type='datetime' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <!--<formula part='week'>CAST((((FLOOR(CAST(%3 AS LONG) / 86400000) - DAYOFWEEK(%3) ) - (FLOOR(CAST(%2 AS LONG) / 86400000) - DAYOFWEEK(%2))) / 7) AS INTEGER)</formula>-->
+      <formula part='week'>DATEDIFF(&apos;ww&apos;,%2,%3)</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+      <argument type='date' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <!--<formula part='week'>CAST((((FLOOR(CAST(%3 AS LONG) / 86400000) - DAYOFWEEK(%3) ) - (FLOOR(CAST(%2 AS LONG) / 86400000) - DAYOFWEEK(%2))) / 7) AS INTEGER)</formula>-->
+      <formula part='week'>DATEDIFF(&apos;ww&apos;,%2,%3)</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+      <argument type='datetime' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <!--<formula part='week'>CAST((((FLOOR(CAST(%3 AS LONG) / 86400000) - DAYOFWEEK(%3) ) - (FLOOR(CAST(%2 AS LONG) / 86400000) - DAYOFWEEK(%2))) / 7) AS INTEGER)</formula>-->
+      <formula part='week'>DATEDIFF(&apos;ww&apos;,%2,%3)</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+      <argument type='date' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <formula part='week'>IIF(%4 = 1, CAST(((FLOOR(CAST(%3 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %3)) - (FLOOR(CAST(%2 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %2))) / 7 AS LONG), DATEDIFF(&apos;ww&apos;,%2,%3))</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+      <argument type='datetime' />
+      <argument type='localstr' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <formula part='week'>IIF(%4 = 1, CAST(((FLOOR(CAST(%3 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %3)) - (FLOOR(CAST(%2 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %2))) / 7 AS LONG), DATEDIFF(&apos;ww&apos;,%2,%3))</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='datetime' />
+      <argument type='date' />
+      <argument type='localstr' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <formula part='week'>IIF(%4 = 1, CAST(((FLOOR(CAST(%3 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %3)) - (FLOOR(CAST(%2 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %2))) / 7 AS LONG), DATEDIFF(&apos;ww&apos;,%2,%3))</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+      <argument type='datetime' />
+      <argument type='localstr' />
+    </date-function>
+    <date-function name='DATEDIFF' return-type='int'>
+      <formula>DATEDIFF(%1,%2,%3)</formula>
+      <formula part='year'>DATEDIFF(&apos;yy&apos;,%2,%3)</formula>
+      <formula part='quarter'>DATEDIFF(&apos;q&apos;,%2,%3)</formula>
+      <formula part='month'>DATEDIFF(&apos;m&apos;,%2,%3)</formula>
+      <formula part='dayofyear'>DATEDIFF(&apos;dy&apos;,%2,%3)</formula>
+      <formula part='day'>DATEDIFF(&apos;d&apos;,%2,%3)</formula>
+      <formula part='weekday'>DATEDIFF(&apos;dw&apos;,%2,%3)</formula>
+      <formula part='week'>IIF(%4 = 1, CAST(((FLOOR(CAST(%3 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %3)) - (FLOOR(CAST(%2 AS LONG) / 86400000) - EXTRACT(ISODOW FROM %2))) / 7 AS LONG), DATEDIFF(&apos;ww&apos;,%2,%3))</formula>
+      <formula part='hour'>DATEDIFF(&apos;hh&apos;,%2,%3)</formula>
+      <formula part='minute'>DATEDIFF(&apos;mi&apos;,%2,%3)</formula>
+      <formula part='second'>DATEDIFF(&apos;ss&apos;,%2,%3)</formula>
+      <argument type='localstr' />
+      <argument type='date' />
+      <argument type='date' />
+      <argument type='localstr' />
+    </date-function>
+    <!-- unsupported functions -->
+    <remove-function name='SPLIT'>
+      <argument type='str' />
+      <argument type='localstr' />
+      <argument type='localint' />
+    </remove-function>
+   </function-map>
+
+   <supported-aggregations>
+    <aggregation value='AGG_COUNT'/>
+    <aggregation value='AGG_COUNTD'/>
+    <aggregation value='AGG_SUM'/>
+    <aggregation value='AGG_AVG'/>
+    <aggregation value='AGG_MIN'/>
+    <aggregation value='AGG_MAX'/>
+    <aggregation value='AGG_STDEV'/>
+    <aggregation value='AGG_STDEVP'/>
+    <aggregation value='AGG_VAR'/>
+    <aggregation value='AGG_VARP'/>
+    <aggregation value='AGG_COVAR'/>
+    <aggregation value='AGG_COVARP'/>
+    <aggregation value='AGG_CORR'/>
+    <aggregation value='AGG_SUM_XSQR'/>
+    <aggregation value='AGG_COLLECT'/>
+    <aggregation value='AGG_ATTR'/>
+    <aggregation value='AGG_YEAR'/>
+    <aggregation value='AGG_QTR'/>
+    <aggregation value='AGG_MONTH'/>
+    <aggregation value='AGG_DAY'/>
+    <aggregation value='AGG_WEEK'/>
+    <aggregation value='AGG_WEEKDAY'/>
+    <aggregation value='AGG_MONTHYEAR'/>
+    <aggregation value='AGG_MDY'/>
+    <aggregation value='AGG_HOUR'/>
+    <aggregation value='AGG_MINUTE'/>
+    <aggregation value='AGG_SECOND'/>
+    <aggregation value='TRUNC_YEAR'/>
+    <aggregation value='TRUNC_QTR'/>
+    <aggregation value='TRUNC_MONTH'/>
+    <aggregation value='TRUNC_DAY'/>
+    <aggregation value='TRUNC_WEEK'/>
+    <aggregation value='TRUNC_HOUR'/>
+    <aggregation value='TRUNC_MINUTE'/>
+    <aggregation value='TRUNC_SECOND'/>
+   </supported-aggregations>
+
+   <sql-format>
+    <format-date-literal formula="CAST('%1' AS DATE)" format='yyyy-MM-dd' />
+    <format-datetime-literal formula="CAST('%1' AS DATETIME)" format='yyyy-MM-dd HH:mm:ss.SSS' />
+
+    <format-null>
+     <local-type name='date' value='CAST(NULL AS DATE)' />
+     <local-type name='datetime' value='CAST(NULL AS TIMESTAMP)' />
+    </format-null>
+
+    <!-- doesn't seem to have any effect
+    <start-of-week-offset value='1' /> -->
+
+    <supported-joins>
+    </supported-joins>
+   </sql-format>
+</dialect>

+ 38 - 0
x-pack/plugin/sql/connectors/tableau/connector/manifest.xml

@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<connector-plugin class='elasticsearch-jdbc' superclass='jdbc' plugin-version='1.0.0' name='Elasticsearch' version='0.0.0'>
+  <vendor-information>
+    <company name='Elastic' />
+    <support-link url='https://www.elastic.co' />
+    <driver-download-link url="https://www.elastic.co/downloads/jdbc-client"/>
+  </vendor-information>
+  <connection-customization class="elasticsearch-jdbc" enabled="true" version="1.0">
+    <vendor name="Elastic"/>
+    <driver name="Elasticsearch JDBC driver"/>
+    <customizations>
+      <customization name="CAP_SELECT_INTO" value="no"/>
+      <customization name="CAP_SELECT_TOP_INTO" value="no"/>
+      <customization name="CAP_CREATE_TEMP_TABLES" value="no"/>
+      <customization name="CAP_QUERY_BOOLEXPR_TO_INTEXPR" value="no"/>
+      <customization name="CAP_QUERY_GROUP_BY_ALIAS" value="yes"/>
+      <customization name="CAP_QUERY_GROUP_BY_BOOL" value="yes"/>
+      <customization name="CAP_QUERY_GROUP_BY_DEGREE" value="yes"/>
+      <customization name="CAP_QUERY_INOUT_JOINS" value="no"/>
+      <customization name="CAP_QUERY_SORT_BY" value="no"/>
+      <customization name="CAP_QUERY_SUBQUERIES" value="no"/>
+      <customization name="CAP_QUERY_SUPPORTS_LODJOINS" value="no"/>
+      <customization name="CAP_QUERY_TOP_0" value="no"/>
+      <customization name="CAP_QUERY_TOP_N" value="no"/>
+      <customization name="CAP_QUERY_NAKED_JOINS" value="no"/>
+      <customization name="CAP_JDBC_EXPORT_DATA_BATCH" value="no"/>
+      <customization name="CAP_JDBC_METADATA_READ_FOREIGNKEYS" value="no"/>
+      <customization name="CAP_JDBC_METADATA_READ_PRIMARYKEYS" value="no"/>
+      <customization name="CAP_SUPPORTS_UNION" value="no"/>
+      <customization name="CAP_JDBC_SUPPRESS_ENUMERATE_SCHEMAS" value="yes"/>
+      <customization name="CAP_SUPPORTS_SPLIT_FROM_LEFT" value="no"/>
+      <customization name="CAP_SUPPORTS_SPLIT_FROM_RIGHT" value="no"/>
+    </customizations>
+  </connection-customization>
+  <connection-dialog file='connection-dialog.tcd'/>
+  <connection-resolver file="connectionResolver.tdr"/>
+  <dialect file='dialect.tdd'/>
+</connector-plugin>

+ 269 - 0
x-pack/plugin/sql/connectors/tableau/package.sh

@@ -0,0 +1,269 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+set -e
+
+TSA_URL=http://timestamp.digicert.com
+
+TAB_SDK_REPO=https://github.com/tableau/connector-plugin-sdk
+TAB_SDK_TAG="tdvt-2.1.9"
+
+MY_NAME="Packager for Elastic's Tableau connector to Elasticsearch"
+MY_FILE=$(basename $0)
+MY_WORKSPACE=$(realpath ${PACKAGE_WORKSPACE:-build})
+MY_TOP_DIR=$(dirname $(realpath $0))
+SRC_DIR=connector
+
+TACO_CLASS=$(xmllint \
+    --xpath '//connector-plugin/@class' $MY_TOP_DIR/$SRC_DIR/manifest.xml \
+    | awk -F\" '{print $2}')
+
+# SDK generated TACO name
+OUT_TACO=$TACO_CLASS.taco
+
+function log()
+{
+    if [ -t 1 ]; then
+        echo -e "$*"
+    else
+        logger ${MY_FILE##*/} ": " "$*"
+    fi
+}
+
+function die()
+{
+    log "ERROR: $*"
+    exit 1
+}
+
+function package() {
+    if [ ! -d $MY_WORKSPACE ]; then
+        mkdir -p $MY_WORKSPACE
+        touch $MY_WORKSPACE/.workspace
+    fi
+
+    pushd . 1>/dev/null
+    trap 'popd 1>/dev/null' EXIT
+    cd $MY_WORKSPACE
+
+    rm -rfv $MY_WORKSPACE/$SRC_DIR
+    cp -rv $MY_TOP_DIR/$SRC_DIR $MY_WORKSPACE
+
+    # patch version tag in manifest file, filtering out any -SNAPSHOT
+    echo -e "cd //connector-plugin/@version\nset ${TACO_VERSION%-*}\nsave" |\
+        xmllint --shell $MY_WORKSPACE/$SRC_DIR/manifest.xml
+
+    # check out TDVT SDK
+    SDK_DIR=${TAB_SDK_REPO##*/}
+    if [ -d $SDK_DIR ]; then
+        cd $SDK_DIR
+        git checkout $TAB_SDK_TAG
+        cd ..
+    else
+        git clone --depth 1 --branch $TAB_SDK_TAG $TAB_SDK_REPO
+    fi
+
+    # install environment
+    cd $SDK_DIR/connector-packager
+    python3 -m venv .venv
+    source .venv/bin/activate
+    python3 setup.py install
+
+    # finally, create the connector
+    python -m connector_packager.package $MY_WORKSPACE/$SRC_DIR
+    cp -f packaged-connector/$OUT_TACO $MY_WORKSPACE/$ES_TACO
+
+    log "TACO packaged under: $MY_WORKSPACE/$ES_TACO"
+}
+
+function sha() {
+    cd $MY_WORKSPACE
+    sha512sum $ES_TACO > $ES_TACO.sha512
+}
+
+# Vars:
+#   read: CMD_ASM, CMD_SIGN
+#   set:  ES_TACO, TACO_VERSION, SIGN_PARAMS
+function read_cmd_params() {
+    while [ $# -gt 0 ]; do
+        key=${1%=*}
+        val=${1#*=}
+        case $key in
+            version)
+                if [ ! -z $TACO_VERSION ]; then
+                    die "parameter 'version' already set to: $TACO_VERSION"
+                fi
+                TACO_VERSION=$val
+                ;;
+            keystore)
+                if [ ! -z $SIGN_KEYSTORE ]; then
+                    die "parameter 'keystore' already set to: $SIGN_KEYSTORE"
+                fi
+                SIGN_KEYSTORE=$(realpath $val)
+                ;;
+            alias)
+                if [ ! -z $SIGN_ALIAS ]; then
+                    die "parameter 'alias' already set to: $SIGN_ALIAS"
+                fi
+                SIGN_ALIAS=$val
+                ;;
+            storepassfile)
+                if [ ! -z $SIGN_STOREPASSFILE ]; then
+                    die "parameter 'storepassfile' already set."
+                fi
+                SIGN_STOREPASSFILE=$val
+                ;;
+            keypassfile)
+                if [ ! -z $SIGN_KEYPASSFILE ]; then
+                    die "parameter 'keypassfile' already set."
+                fi
+                SIGN_KEYPASSFILE=$val
+                ;;
+            onepass)
+                if [ ! -z $SIGN_ONEPASS ]; then
+                    die "parameter 'onepass' already set."
+                fi
+                SIGN_ONEPASS=$val
+                ;;
+            *)
+                die "Unknown parameter: $key"
+                ;;
+        esac
+        shift
+    done
+
+    if [ $CMD_ASM -gt 0 ]; then
+        if [ -z $TACO_VERSION ]; then
+            die "parameter 'version' is mandatory for assambling."
+        fi
+        ES_TACO=$TACO_CLASS-$TACO_VERSION.taco
+    fi
+
+    if [ $CMD_SIGN -gt 0 ]; then
+        if [ -z $SIGN_KEYSTORE ] || [ -z $SIGN_ALIAS ]; then
+            die "parameters 'keystore' and 'alias' are mandatory for signing."
+        fi
+
+        SIGN_PARAMS="$SIGN_ALIAS"
+        SIGN_PARAMS="$SIGN_PARAMS -keystore $SIGN_KEYSTORE"
+        SIGN_PARAMS="$SIGN_PARAMS -tsa $TSA_URL"
+
+        if [ ! -z $SIGN_ONEPASS ]; then
+            if [ ! -z $SIGN_STOREPASSFILE ] || [ ! -z $SIGN_KEYPASSFILE ]; then
+                die "parameter 'onepass' cannot be used together with " \
+                    "'storepassfile' or 'keypassfile'."
+            fi
+            SIGN_PARAMS="$SIGN_PARAMS -storepass $SIGN_ONEPASS"
+            SIGN_PARAMS="$SIGN_PARAMS -keypass $SIGN_ONEPASS"
+        else
+            if [ ! -z $SIGN_STOREPASSFILE ]; then
+                pass=$(cat $SIGN_STOREPASSFILE)
+                SIGN_PARAMS="$SIGN_PARAMS -storepass $pass"
+            fi
+            if [ ! -z $SIGN_KEYPASSFILE ]; then
+                pass=$(cat $SIGN_KEYPASSFILE)
+                SIGN_PARAMS="$SIGN_PARAMS -keypass $pass"
+            fi
+        fi
+    fi
+}
+
+function sign() {
+    for taco in $(ls -t $MY_WORKSPACE/*.taco 2>/dev/null); do
+        jarsigner $taco $SIGN_PARAMS
+        jarsigner -verify -verbose -certs $taco
+
+        log "TACO signed under: $taco"
+        break
+    done
+
+    if [ -z $taco ]; then
+        die "No connector to sign found under: $MY_WORKSPACE/" \
+            "\nCall 'assemble' first."
+    fi
+
+}
+
+function clean() {
+    if [ -f $MY_WORKSPACE/.workspace ]; then
+        rm -rf $MY_WORKSPACE
+    else
+        die "Not a workspace: $MY_WORKSPACE"
+    fi
+}
+
+function usage() {
+    log $MY_NAME
+    log
+    log "Usage: $MY_FILE <command>"
+    log
+    log "Commands:"
+    log "  asm <version parameter>    : assemble the TACO file"
+    log "  sign <signing parameters>  : sign the TACO file"
+    log "  pack <ver and sign params> : assemble and sign"
+    log "  clean                      : remove the workspace"
+    log
+    log "Params take the form key=value with following keys:"
+    log "  version       : version of the TACO to produce; mandatory;"
+    log "  keystore      : path to keystore to use; mandatory;"
+    log "  storepassfile : keystore password file; optional;"
+    log "  keypassfile   : private key password file; optional;"
+    log "  onepass       : password for both the keystore and the "
+    log "                  private key; optional;"
+    log "  alias         : alias for the keystore entry; mandatory."
+    log
+    log "All building is done under workspace: $MY_WORKSPACE"
+    log "Can be changed with PACKAGE_WORKSPACE environment variable."
+    log
+    log "Example:"
+    log "  ./$MY_FILE asm version=7.10.1"
+    log "  ./$MY_FILE sign keystore=keystore_file alias=alias_name"\
+            "storepassfile=password_file"
+    log "  ./$MY_FILE pack version=7.10.2 keystore=keystore_file"\
+            "alias=alias_name onepass=password"
+    log
+}
+
+if [ $# -lt 1 ]; then
+    usage
+    die "missing command"
+fi
+
+CMD_ASM=0
+CMD_SIGN=0
+
+case $1 in
+    asm|assemble)
+        CMD_ASM=1
+        shift
+        read_cmd_params $*
+        package
+        sha
+        ;;
+    sign)
+        CMD_SIGN=1
+        shift
+        read_cmd_params $*
+        sign
+        ;;
+    pack|package)
+        CMD_ASM=1
+        CMD_SIGN=1
+        shift
+        read_cmd_params $*
+        package
+        sign
+        sha
+        ;;
+    clean)
+        clean
+        ;;
+    *)
+        usage
+        ;;
+esac

+ 116 - 0
x-pack/plugin/sql/connectors/tableau/tdvt/README.md

@@ -0,0 +1,116 @@
+# Testing the Tableau connector for Elasticsearch
+
+This folder contains the files needed to run Tableau's TDVT suite, to validate the connector's applicability.
+
+## Testing requirements
+
+Running the TDVT tests require a working instance of Elasticsearch (local or remote) and a Windows desktop with:
+* a Python 3 installation;
+* Tableau Desktop, licensed (the trial mode won't suffice for a JDBC connector), past or at 2019.4 release.
+* the Elastic JDBC driver available.
+
+All these should be at their latest released version.
+
+**Note**: If running Elasticsearch remotely, both machines must be (1) time-synchronized and (2) have the same locale settings (i.e.: the calendars on both must start on the same day of week, same date format etc.).
+
+## Elasticsearch setup
+
+The Elasticsearch server should be on the latest release, have the SQL plugin installed (i.e. the "default" distribution) and a valid license for it (can be a temporary trial license).
+
+No other settings need to be changed from default, with one exception: the inline script compilation rate needs to be elevated from the default (current: 75/5m). This dynamic cluster setting is called `script.context.aggs.max_compilations_rate` starting with [7.9](https://www.elastic.co/guide/en/elasticsearch/reference/master/circuit-breaker.html#script-compilation-circuit-breaker) releases (for aggregations) and `script.max_compilations_rate` up to [7.8](https://www.elastic.co/guide/en/elasticsearch/reference/7.8/circuit-breaker.html#script-compilation-circuit-breaker). The minimum high-enough value might be hard to get right, but a fast run of the TDVT tests yield a ~7 tests/sec, so with a generous margin, just for testing, one could set a value of `1000/1m`.
+
+The data for running the TDVT suite needs to be loaded into Elasticsearch prior to running the tests. This can be achieved in a few ways:
+
+### 1. Import using Elastic's ODBC driver testing suite
+
+ODBC's driver test suite is a Python application that, among other things, will load the testing data into a running Elasticsearch instance.
+It requires a Python 3 installation with [requests](python-requests.org) and [psutils](https://pypi.org/project/psutil/) PIP modules installed.
+
+Clone it from its [Github repo](https://github.com/elastic/elasticsearch-sql-odbc/) and run the following from within the top repo directory:
+```
+python3 ./test/integration/ites.py -p http://user:password@host:port -tx
+```
+where the `user`, `password`, `host` and `port` are the credentials and URL to access the Elasticsearch instance.
+
+This will download the TDVT CSV data sources from their [connector-plugin-sdk](https://github.com/tableau/connector-plugin-sdk/tree/master/tests/datasets/TestV1) repository and upload them to the destination test Elasticsearch instance. (It will also install the needed pipelines, templates/mappings to accomodate the source data, along with other test data irrelevant for TDVT testing -- just ignore or delete the other created indices).
+
+### 2. Reindex from remote
+
+Note: this requires some familiarity with Elasticsearch.
+
+If there is an available other Elasticsearch instance running, that has the test data loaded already, this data can be imported through the `_reindex` [API](www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html). Follow the two steps detailed in [Reindex from a remote cluster](https://www.elastic.co/guide/en/elasticsearch/reference/current/reindex-upgrade-remote.html).
+
+<TODO: detailed sequence of steps>
+
+### 3. Import using Elastic's Logstash application
+
+[Logstash](https://www.elastic.co/guide/en/logstash/current/running-logstash-windows.html) is a Java application that can ingest data from various sources and in various formats and upload them into an Elasticsearch instance.
+
+Note that Logstash will add a few extra fields per row ("document" in Elasticsearch lingo); these shouldn't interfere with the testing, however.
+
+1. Download TDVT's data files [Calcs.csv](https://raw.githubusercontent.com/tableau/connector-plugin-sdk/tdvt-2.1.9/tests/datasets/TestV1/Calcs.csv) and [Staples_utf8.csv](https://raw.githubusercontent.com/tableau/connector-plugin-sdk/tdvt-2.1.9/tests/datasets/TestV1/Staples_utf8.csv) and place them into a directory that will be reachable by Logstash.
+
+2. Create the Elasticsearch indices `calcs` and `staples` and use for them the [mappings](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html) under these links: [calcs](https://github.com/elastic/elasticsearch-sql-odbc/blob/577cd2fa1ed257e42081a082682c8c089b179565/test/integration/data.py#L27) and [stapes](https://github.com/elastic/elasticsearch-sql-odbc/blob/577cd2fa1ed257e42081a082682c8c089b179565/test/integration/data.py#L87). Create an ingest [pipeline](https://www.elastic.co/guide/en/elasticsearch/reference/current/put-pipeline-api.html) called `calcs-pipeline` with the definition [here](https://github.com/elastic/elasticsearch-sql-odbc/blob/577cd2fa1ed257e42081a082682c8c089b179565/test/integration/data.py#L62).
+
+3. Adapt the [config file](https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html#configuration-file-structure) under the `logstash` folder, updating the <path>, <host> and <password> tags in it.
+
+4. Relaunch Logstash using the updated config file in previous step and wait until the files have been ingested. `calcs` index will need to have 17 documents and `staples` 54860.
+
+
+## Running TDVT
+
+### Automated
+
+1. Place Elasticsearch JDBC driver into [Tableau's driver folder](https://help.tableau.com/current/pro/desktop/en-us/examples_otherdatabases_jdbc.htm) under: `C:\Program Files\Tableau\Drivers`.
+
+2. Place the `.taco` file either in Tableau's dedicated connectors directory, `C:\Users\[Windows User]\Documents\My Tableau Repository\Connectors`, or a custom one ("<taco dir path>").
+
+3. Use the `tdvt_run.py` application, that clone the TDVT SDK repo, setup config files and launch the TDVT run:
+    ```
+    python3 ./tdvt_run.py -u "http://user:pass@elastic-host:9200" -t <taco dir path>
+    ```
+
+### Manually
+
+Setting up the TDVT testing involves following the steps detailed in the [official documentation](https://tableau.github.io/connector-plugin-sdk/docs/tdvt). The "fragment" in parantheses reference the respective chapters in the documentation. It is recommended to execute each test run starting afresh.
+
+1. Same as in the automated testing.
+
+2. Create new Tableau data sources for the `calcs` and `Staple` tables (#`Test a new data source`), or, alternatively, use those available already in this repo.
+	To set up new sources, launch Tableau from command line with the following parameters (PowerShell example):
+	```
+	.\tableau.exe -DConnectPluginsPath=<path> -DDisableVerifyConnectorPluginSignature=true
+	```
+	where `<path>` is either the path to the directory containing the `.taco` connector *or* the path to the directory containing the connector directory, if this isn't yet packaged.
+  
+	**Note**: When connecting, make sure you pass the `timezone=Z` parameter into the `Additional settings` field of the connection dialog. This sets the timezone for the time data to UTC; if this isn't set, the JDBC driver will use JVM's/system's time zone, which will then result in some failed tests if the machine's not set to the UTC timezone.
+
+	Save the TDS files as `cast_calcs.elastic.tds` and `Staples.elastic.tds`
+
+3. Setup a TDVT "workspace" (#`Set up`), i.e. a directory containing the test files.
+	Either package TDVT and install it as a Python PIP module (recommended, if [working](https://github.com/tableau/connector-plugin-sdk/issues/534)), or simply copy the `tdvt` directory of the repo into the "workspace" directory. Invoking the TDVT will then be done as `py -3 -m tdvt.tdvt <params>`, or `py -3 .\tdvt\tdvt_launcher.py <params>`, respectively. In the steps below the invokation will be indicated by the `$TDVT` call.
+	```
+	$TDVT action --setup
+	```
+
+	Copy/move the above saved `*.tds` files into the just created `tds` directory in the workspace.
+	Edit `config/tdvt/tdvt_override.ini` to update `TAB_CLI_EXE_X64` definition.
+
+4. Generate the tests by invoking TDVT as follows:
+
+	```
+	$TDVT action --add_ds elastic
+	```
+
+	When asked for a password, use the same value as in step "2." above when connecting to Elasticsearch.
+	For the "logical query config" use `simple_lower`.
+
+	Edit the `elastic.ini` file in the `config` directory in the workspace and add the following line under the `[Datasource]` section: `CommandLineOverride = -DConnectPluginsPath=<path> -DDisableVerifyConnectorPluginSignature=true`, where `<path>` has the same value as in step "2.".
+
+5. Run the tests:
+
+	```
+	$TDVT run elastic
+	```
+
+	**Note**: If running on a busy machine, TDVT's thread allocation can be throttled with the `-t <threads>` argument, where <threads> should take the value of available CPU execution units, or even `1` if running on a slower VM.

+ 56 - 0
x-pack/plugin/sql/connectors/tableau/tdvt/logstash/logstash.conf

@@ -0,0 +1,56 @@
+input {
+  file {
+    path => "</path/to/Calcs.csv>"
+    start_position => "beginning"
+    sincedb_path => "<path to Logstash'es sincedb>"
+    tags => ["calcs"]
+  }
+  file {
+    path => "</path/to/Staples_utf8.csv>"
+    start_position => "beginning"
+    sincedb_path => "<path to Logstash'es sincedb>"
+    tags => ["staples"]
+  }
+}
+
+filter {
+  if "calcs" in [tags] {
+      csv {
+        separator => ","
+        columns => ["key","num0","num1","num2","num3","num4","str0","str1","str2","str3","int0","int1","int2",
+        "int3","bool0","bool1","bool2","bool3","date0","date1","date2","date3","time0","time1","datetime0","datetime1","zzz"]
+      }
+  } else if "staples" in [tags] {
+      csv {
+        separator => ","
+        columns => ["Item Count","Ship Priority","Order Priority","Order Status","Order Quantity","Sales Total",
+        "Discount","Tax Rate","Ship Mode","Fill Time","Gross Profit","Price","Ship Handle Cost","Employee Name",
+        "Employee Dept","Manager Name","Employee Yrs Exp","Employee Salary","Customer Name","Customer State",
+        "Call Center Region","Customer Balance","Customer Segment","Prod Type1","Prod Type2","Prod Type3","Prod Type4",
+        "Product Name","Product Container","Ship Promo","Supplier Name","Supplier Balance","Supplier Region",
+        "Supplier State","Order ID","Order Year","Order Month","Order Day","Order Date","Order Quarter","Product Base Margin",
+        "Product ID","Receive Time","Received Date","Ship Date","Ship Charge","Total Cycle Time","Product In Stock","PID","Market Segment" ]
+      }
+  }
+}
+
+output {
+    if "calcs" in [tags] {
+        elasticsearch {
+            hosts => "<elastic-host>:9200"
+            index => "calcs"
+            pipeline => "calcs-pipeline"
+            manage_template => false
+            user => "elastic"
+            password => "<password>"
+        }
+    } else if "staples" in [tags] {
+        elasticsearch {
+            hosts => "<elastic-host>:9200"
+            index => "staples"
+            manage_template => false
+            user => "elastic"
+            password => "<password>"
+        }
+    }
+}

+ 21 - 0
x-pack/plugin/sql/connectors/tableau/tdvt/tds/LICENSE.txt

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Tableau
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 766 - 0
x-pack/plugin/sql/connectors/tableau/tdvt/tds/Staples.elastic.tds

@@ -0,0 +1,766 @@
+<?xml version='1.0' encoding='utf-8' ?>
+
+<!-- build 20202.20.0525.1210                               -->
+<datasource formatted-name='federated.1g70urs0o5vyl31a5rr9a1i0lbz4' inline='true' source-platform='win' version='18.1' xmlns:user='http://www.tableausoftware.com/xml/user'>
+  <document-format-change-manifest>
+    <_.fcp.ObjectModelEncapsulateLegacy.true...ObjectModelEncapsulateLegacy />
+    <_.fcp.ObjectModelTableType.true...ObjectModelTableType />
+    <_.fcp.SchemaViewerObjectModel.true...SchemaViewerObjectModel />
+  </document-format-change-manifest>
+  <connection class='federated'>
+    <named-connections>
+      <named-connection caption='127.0.0.1' name='leaf'>
+        <connection class='elasticsearch_jdbc' dbname='elasticsearch' one-time-sql='' port='9200' server='127.0.0.1' sslmode='' username='elastic' warehouse='timezone=Z' tdvtconnection='elastic_connection'  />
+      </named-connection>
+    </named-connections>
+    <_.fcp.ObjectModelEncapsulateLegacy.false...relation connection='leaf' name='staples' table='[staples]' type='table' />
+    <_.fcp.ObjectModelEncapsulateLegacy.true...relation connection='leaf' name='staples' table='[staples]' type='table' />
+    <metadata-records>
+      <metadata-record class='column'>
+        <remote-name>Call Center Region</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Call Center Region]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Call Center Region</remote-alias>
+        <ordinal>1</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Customer Balance</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Customer Balance]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Customer Balance</remote-alias>
+        <ordinal>2</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Customer Name</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Customer Name]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Customer Name</remote-alias>
+        <ordinal>3</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Customer Segment</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Customer Segment]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Customer Segment</remote-alias>
+        <ordinal>4</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Customer State</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Customer State]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Customer State</remote-alias>
+        <ordinal>5</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Discount</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Discount]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Discount</remote-alias>
+        <ordinal>6</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Employee Dept</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Employee Dept]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Employee Dept</remote-alias>
+        <ordinal>7</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Employee Name</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Employee Name]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Employee Name</remote-alias>
+        <ordinal>8</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Employee Salary</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Employee Salary]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Employee Salary</remote-alias>
+        <ordinal>9</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Employee Yrs Exp</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Employee Yrs Exp]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Employee Yrs Exp</remote-alias>
+        <ordinal>10</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Fill Time</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Fill Time]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Fill Time</remote-alias>
+        <ordinal>11</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Gross Profit</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Gross Profit]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Gross Profit</remote-alias>
+        <ordinal>12</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Item Count</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[Item Count]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Item Count</remote-alias>
+        <ordinal>13</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Manager Name</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Manager Name]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Manager Name</remote-alias>
+        <ordinal>14</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Market Segment</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Market Segment]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Market Segment</remote-alias>
+        <ordinal>15</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Date</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[Order Date]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Date</remote-alias>
+        <ordinal>16</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Day</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[Order Day]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Day</remote-alias>
+        <ordinal>17</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order ID</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Order ID]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order ID</remote-alias>
+        <ordinal>18</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Month</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[Order Month]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Month</remote-alias>
+        <ordinal>19</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Priority</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Order Priority]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Priority</remote-alias>
+        <ordinal>20</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Quantity</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Order Quantity]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Quantity</remote-alias>
+        <ordinal>21</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Quarter</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Order Quarter]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Quarter</remote-alias>
+        <ordinal>22</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Status</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Order Status]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Status</remote-alias>
+        <ordinal>23</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Order Year</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[Order Year]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Order Year</remote-alias>
+        <ordinal>24</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>PID</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[PID]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>PID</remote-alias>
+        <ordinal>25</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Price</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Price]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Price</remote-alias>
+        <ordinal>26</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Prod Type1</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Prod Type1]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Prod Type1</remote-alias>
+        <ordinal>27</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Prod Type2</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Prod Type2]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Prod Type2</remote-alias>
+        <ordinal>28</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Prod Type3</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Prod Type3]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Prod Type3</remote-alias>
+        <ordinal>29</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Prod Type4</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Prod Type4]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Prod Type4</remote-alias>
+        <ordinal>30</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Product Base Margin</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Product Base Margin]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Product Base Margin</remote-alias>
+        <ordinal>31</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Product Container</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Product Container]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Product Container</remote-alias>
+        <ordinal>32</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Product ID</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Product ID]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Product ID</remote-alias>
+        <ordinal>33</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Product In Stock</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Product In Stock]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Product In Stock</remote-alias>
+        <ordinal>34</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Product Name</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Product Name]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Product Name</remote-alias>
+        <ordinal>35</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Receive Time</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Receive Time]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Receive Time</remote-alias>
+        <ordinal>36</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Received Date</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[Received Date]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Received Date</remote-alias>
+        <ordinal>37</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Sales Total</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Sales Total]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Sales Total</remote-alias>
+        <ordinal>38</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Ship Charge</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Ship Charge]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Ship Charge</remote-alias>
+        <ordinal>39</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Ship Date</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[Ship Date]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Ship Date</remote-alias>
+        <ordinal>40</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Ship Handle Cost</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Ship Handle Cost]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Ship Handle Cost</remote-alias>
+        <ordinal>41</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Ship Mode</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Ship Mode]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Ship Mode</remote-alias>
+        <ordinal>42</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Ship Priority</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Ship Priority]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Ship Priority</remote-alias>
+        <ordinal>43</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Ship Promo</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Ship Promo]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Ship Promo</remote-alias>
+        <ordinal>44</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Supplier Balance</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Supplier Balance]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Supplier Balance</remote-alias>
+        <ordinal>45</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Supplier Name</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Supplier Name]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Supplier Name</remote-alias>
+        <ordinal>46</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Supplier Region</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Supplier Region]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Supplier Region</remote-alias>
+        <ordinal>47</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Supplier State</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[Supplier State]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Supplier State</remote-alias>
+        <ordinal>48</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Tax Rate</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Tax Rate]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Tax Rate</remote-alias>
+        <ordinal>49</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>Total Cycle Time</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[Total Cycle Time]</local-name>
+        <parent-name>[staples]</parent-name>
+        <remote-alias>Total Cycle Time</remote-alias>
+        <ordinal>50</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[staples_1BF3B1DA9B1E4629AEF2659485D0D340]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+    </metadata-records>
+  </connection>
+  <aliases enabled='yes' />
+  <column datatype='string' name='[Customer State]' role='dimension' semantic-role='[State].[Name]' type='nominal' />
+  <column datatype='integer' name='[Order Day]' role='dimension' type='quantitative' />
+  <column datatype='integer' name='[Order Month]' role='dimension' type='quantitative' />
+  <column datatype='integer' name='[Order Year]' role='dimension' type='quantitative' />
+  <column datatype='string' name='[Supplier State]' role='dimension' semantic-role='[State].[Name]' type='nominal' />
+  <_.fcp.ObjectModelTableType.true...column caption='staples' datatype='table' name='[__tableau_internal_object_id__].[staples_1BF3B1DA9B1E4629AEF2659485D0D340]' role='measure' type='quantitative' />
+  <layout _.fcp.SchemaViewerObjectModel.false...dim-percentage='0.5' _.fcp.SchemaViewerObjectModel.false...measure-percentage='0.4' dim-ordering='alphabetic' measure-ordering='alphabetic' show-structure='true' />
+  <semantic-values>
+    <semantic-value key='[Country].[Name]' value='&quot;USA&quot;' />
+  </semantic-values>
+  <_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
+    <objects>
+      <object caption='staples' id='staples_1BF3B1DA9B1E4629AEF2659485D0D340'>
+        <properties context=''>
+          <relation connection='leaf' name='staples' table='[staples]' type='table' />
+        </properties>
+      </object>
+    </objects>
+  </_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
+</datasource>

+ 424 - 0
x-pack/plugin/sql/connectors/tableau/tdvt/tds/cast_calcs.elastic.tds

@@ -0,0 +1,424 @@
+<?xml version='1.0' encoding='utf-8' ?>
+
+<!-- build 20202.20.0525.1210                               -->
+<datasource formatted-name='federated.1fpbzog1e3tyyl10dzgub1v3by4l' inline='true' source-platform='win' version='18.1' xmlns:user='http://www.tableausoftware.com/xml/user'>
+  <document-format-change-manifest>
+    <_.fcp.ObjectModelEncapsulateLegacy.true...ObjectModelEncapsulateLegacy />
+    <_.fcp.ObjectModelTableType.true...ObjectModelTableType />
+    <_.fcp.SchemaViewerObjectModel.true...SchemaViewerObjectModel />
+  </document-format-change-manifest>
+  <connection class='federated'>
+    <named-connections>
+      <named-connection caption='127.0.0.1' name='leaf'>
+        <connection class='elasticsearch_jdbc' dbname='elasticsearch' one-time-sql='' port='9200' server='127.0.0.1' sslmode='' username='elastic' warehouse='timezone=Z' tdvtconnection='elastic_connection'  />
+      </named-connection>
+    </named-connections>
+    <_.fcp.ObjectModelEncapsulateLegacy.false...relation connection='leaf' name='calcs' table='[calcs]' type='table' />
+    <_.fcp.ObjectModelEncapsulateLegacy.true...relation connection='leaf' name='calcs' table='[calcs]' type='table' />
+    <metadata-records>
+      <metadata-record class='column'>
+        <remote-name>bool0</remote-name>
+        <remote-type>11</remote-type>
+        <local-name>[bool0]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>bool0</remote-alias>
+        <ordinal>1</ordinal>
+        <local-type>boolean</local-type>
+        <aggregation>Count</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>bool1</remote-name>
+        <remote-type>11</remote-type>
+        <local-name>[bool1]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>bool1</remote-alias>
+        <ordinal>2</ordinal>
+        <local-type>boolean</local-type>
+        <aggregation>Count</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>bool2</remote-name>
+        <remote-type>11</remote-type>
+        <local-name>[bool2]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>bool2</remote-alias>
+        <ordinal>3</ordinal>
+        <local-type>boolean</local-type>
+        <aggregation>Count</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>bool3</remote-name>
+        <remote-type>11</remote-type>
+        <local-name>[bool3]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>bool3</remote-alias>
+        <ordinal>4</ordinal>
+        <local-type>boolean</local-type>
+        <aggregation>Count</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>date0</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[date0]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>date0</remote-alias>
+        <ordinal>5</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>date1</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[date1]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>date1</remote-alias>
+        <ordinal>6</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>date2</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[date2]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>date2</remote-alias>
+        <ordinal>7</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>date3</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[date3]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>date3</remote-alias>
+        <ordinal>8</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>datetime0</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[datetime0]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>datetime0</remote-alias>
+        <ordinal>9</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>datetime1</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[datetime1]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>datetime1</remote-alias>
+        <ordinal>10</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>int0</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[int0]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>int0</remote-alias>
+        <ordinal>11</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>int1</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[int1]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>int1</remote-alias>
+        <ordinal>12</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>int2</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[int2]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>int2</remote-alias>
+        <ordinal>13</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>int3</remote-name>
+        <remote-type>3</remote-type>
+        <local-name>[int3]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>int3</remote-alias>
+        <ordinal>14</ordinal>
+        <local-type>integer</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>11</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>key</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[key]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>key</remote-alias>
+        <ordinal>15</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>num0</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[num0]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>num0</remote-alias>
+        <ordinal>16</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>num1</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[num1]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>num1</remote-alias>
+        <ordinal>17</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>num2</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[num2]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>num2</remote-alias>
+        <ordinal>18</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>num3</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[num3]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>num3</remote-alias>
+        <ordinal>19</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>num4</remote-name>
+        <remote-type>5</remote-type>
+        <local-name>[num4]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>num4</remote-alias>
+        <ordinal>20</ordinal>
+        <local-type>real</local-type>
+        <aggregation>Sum</aggregation>
+        <precision>7</precision>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>str0</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[str0]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>str0</remote-alias>
+        <ordinal>21</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>str1</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[str1]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>str1</remote-alias>
+        <ordinal>22</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>str2</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[str2]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>str2</remote-alias>
+        <ordinal>23</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>str3</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[str3]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>str3</remote-alias>
+        <ordinal>24</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>time0</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[time0]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>time0</remote-alias>
+        <ordinal>25</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>time1</remote-name>
+        <remote-type>135</remote-type>
+        <local-name>[time1]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>time1</remote-alias>
+        <ordinal>26</ordinal>
+        <local-type>datetime</local-type>
+        <aggregation>Year</aggregation>
+        <contains-null>true</contains-null>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+      <metadata-record class='column'>
+        <remote-name>zzz</remote-name>
+        <remote-type>129</remote-type>
+        <local-name>[zzz]</local-name>
+        <parent-name>[calcs]</parent-name>
+        <remote-alias>zzz</remote-alias>
+        <ordinal>27</ordinal>
+        <local-type>string</local-type>
+        <aggregation>Count</aggregation>
+        <width>32766</width>
+        <contains-null>true</contains-null>
+        <attributes>
+          <attribute datatype='string' name='TypeIsVarchar'>&quot;true&quot;</attribute>
+        </attributes>
+        <_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]</_.fcp.ObjectModelEncapsulateLegacy.true...object-id>
+      </metadata-record>
+    </metadata-records>
+  </connection>
+  <aliases enabled='yes' />
+  <_.fcp.ObjectModelTableType.true...column caption='calcs' datatype='table' name='[__tableau_internal_object_id__].[calcs_C27AE2A9BA5748228EBAF65C2930B3E9]' role='measure' type='quantitative' />
+  <column caption='Bool0' datatype='boolean' name='[bool0]' role='dimension' type='nominal' />
+  <column caption='Bool1' datatype='boolean' name='[bool1]' role='dimension' type='nominal' />
+  <column caption='Bool2' datatype='boolean' name='[bool2]' role='dimension' type='nominal' />
+  <column caption='Bool3' datatype='boolean' name='[bool3]' role='dimension' type='nominal' />
+  <column caption='Date0' datatype='datetime' name='[date0]' role='dimension' type='ordinal' />
+  <column caption='Date1' datatype='datetime' name='[date1]' role='dimension' type='ordinal' />
+  <column caption='Date2' datatype='datetime' name='[date2]' role='dimension' type='ordinal' />
+  <column caption='Date3' datatype='datetime' name='[date3]' role='dimension' type='ordinal' />
+  <column caption='Datetime0' datatype='datetime' name='[datetime0]' role='dimension' type='ordinal' />
+  <column caption='Datetime1' datatype='string' name='[datetime1]' role='dimension' type='nominal' />
+  <column caption='Int0' datatype='integer' name='[int0]' role='measure' type='quantitative' />
+  <column caption='Int1' datatype='integer' name='[int1]' role='measure' type='quantitative' />
+  <column caption='Int2' datatype='integer' name='[int2]' role='measure' type='quantitative' />
+  <column caption='Int3' datatype='integer' name='[int3]' role='measure' type='quantitative' />
+  <column caption='Key' datatype='string' name='[key]' role='dimension' type='nominal' />
+  <column caption='Num0' datatype='real' name='[num0]' role='measure' type='quantitative' />
+  <column caption='Num1' datatype='real' name='[num1]' role='measure' type='quantitative' />
+  <column caption='Num2' datatype='real' name='[num2]' role='measure' type='quantitative' />
+  <column caption='Num3' datatype='real' name='[num3]' role='measure' type='quantitative' />
+  <column caption='Num4' datatype='real' name='[num4]' role='measure' type='quantitative' />
+  <column caption='Str0' datatype='string' name='[str0]' role='dimension' type='nominal' />
+  <column caption='Str1' datatype='string' name='[str1]' role='dimension' type='nominal' />
+  <column caption='Str2' datatype='string' name='[str2]' role='dimension' type='nominal' />
+  <column caption='Str3' datatype='string' name='[str3]' role='dimension' type='nominal' />
+  <column caption='Time0' datatype='datetime' name='[time0]' role='dimension' type='ordinal' />
+  <column caption='Time1' datatype='datetime' name='[time1]' role='dimension' type='ordinal' />
+  <column caption='Zzz' datatype='string' name='[zzz]' role='dimension' type='nominal' />
+  <layout _.fcp.SchemaViewerObjectModel.false...dim-percentage='0.5' _.fcp.SchemaViewerObjectModel.false...measure-percentage='0.4' dim-ordering='alphabetic' measure-ordering='alphabetic' show-structure='true' />
+  <semantic-values>
+    <semantic-value key='[Country].[Name]' value='&quot;USA&quot;' />
+  </semantic-values>
+  <_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
+    <objects>
+      <object caption='calcs' id='calcs_C27AE2A9BA5748228EBAF65C2930B3E9'>
+        <properties context=''>
+          <relation connection='leaf' name='calcs' table='[calcs]' type='table' />
+        </properties>
+      </object>
+    </objects>
+  </_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
+</datasource>

+ 1 - 0
x-pack/plugin/sql/connectors/tableau/tdvt/tds/elastic.password

@@ -0,0 +1 @@
+elastic_connection;<REDACTED>

+ 249 - 0
x-pack/plugin/sql/connectors/tableau/tdvt/tdvt_run.py

@@ -0,0 +1,249 @@
+#!/usr/bin/python3
+#
+# 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.
+#
+
+import subprocess
+import inspect
+import os
+import urllib3
+import re
+import threading
+import ipaddress
+import argparse
+import time
+import getpass
+
+
+TDVT_SDK_NAME = "connector-plugin-sdk"
+TDVT_SDK_REPO = "https://github.com/tableau/" + TDVT_SDK_NAME
+TDVT_SDK_BRANCH = "tdvt-2.1.9"
+TDVT_ES_SCHEME = "simple_lower"
+
+TDVT_RUN_DIR = "run"
+
+TIMEOUTS = {"_default_": 5, "checkout_tdvt_sdk": 60, "setup_workspace": 10, "add_data_source": 300, "run_tdvt": 1800}
+TDVT_LAUNCHER = os.path.join(TDVT_SDK_NAME, "tdvt", "tdvt_launcher.py")
+
+#
+# configs
+TDS_SRC_DIR = "tds"
+TACO_SRC_DIR = "C:\\Users\\" + getpass.getuser() + "\\Documents\\My Tableau Repository\\Connectors"
+TACO_SIGNED = True
+ES_URL = "http://elastic-admin:elastic-password@127.0.0.1:9200"
+
+
+def interact(proc, interactive):
+    # no straigh forward non-blocking read on Win -> char reader in own thread
+    def read_stdout(buff, condition):
+        c = " "
+        while c != "":
+            c = proc.stdout.read(1)
+            condition.acquire()
+            buff.append('\0' if c == "" else c)
+            condition.notify()
+            condition.release()
+
+    buff = [' ']
+    condition = threading.Condition()
+    reader = threading.Thread(target=read_stdout, args=(buff, condition))
+    reader.start()
+
+    interactive.reverse()
+    while len(interactive) > 0 and reader.is_alive():
+        token, answer = interactive.pop()
+        condition.acquire()
+        while buff[-1] != '\0':
+            output = "".join(buff)
+            if token not in output:
+                condition.wait()
+            else:
+                condition.release()
+                proc.stdin.write(answer + '\n')
+                proc.stdin.flush()
+                break
+
+    reader.join()
+
+
+def exe(args, interactive = None, raise_on_retcode = True):
+    with subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+            universal_newlines=True) as proc:
+        if interactive is not None:
+            interact(proc, interactive)
+
+        try:
+            caller = inspect.stack()[1][3]
+            proc.wait(TIMEOUTS[caller] if caller in TIMEOUTS.keys() else TIMEOUTS["_default_"])
+        except subprocess.TimeoutExpired as e:
+            proc.kill()
+        stdout, stderr = proc.communicate()
+        if proc.returncode != 0 and raise_on_retcode:
+            print("command stdout: \n" + stdout)
+            print("command stderr: \n" + stderr)
+            raise Exception("Command exited with code %s: '%s' !" % (proc.returncode, args))
+        return (proc.returncode, stdout, stderr)
+
+def checkout_tdvt_sdk():
+    git_args = ["git", "clone", "--depth", "1", "--branch", TDVT_SDK_BRANCH, TDVT_SDK_REPO]
+    exe(git_args)
+
+def setup_workspace():
+
+    tdvt_args = ["py", "-3", TDVT_LAUNCHER, "action", "--setup"]
+    exe(tdvt_args)
+
+def install_tds_files(tds_src_dir, elastic_url):
+    TDVT_TDS_DIR = "tds"
+
+    def dbname(es_host):
+        try:
+            ipaddress.ip_address(es_host)
+            return es_host
+        except ValueError as ve:
+            pos = es_host.find(".")
+            return es_host if pos <= 0 else es_host[:pos]
+
+    es_url = urllib3.util.parse_url(elastic_url)
+    if ':' in es_url.auth:
+        (es_user, es_pass) = es_url.auth.split(':')
+    else:
+        (es_user, es_pass) = es_url.auth, ""
+
+    for (dirpath, dirnames, filenames) in os.walk(tds_src_dir, topdown=True, followlinks=False):
+        if dirpath != tds_src_dir:
+            break
+        for filename in filenames:
+            if not (filename.endswith(".tds") or filename.endswith(".password")):
+                continue
+            with open(os.path.join(tds_src_dir, filename)) as src:
+                content = src.read()
+                if filename.endswith(".tds"):
+                    content = content.replace("caption='127.0.0.1'", "caption='" + es_url.host + "'")
+                    content = content.replace("dbname='elasticsearch'", "dbname='" + dbname(es_url.host) + "'")
+                    content = content.replace("server='127.0.0.1'", "server='" + es_url.host + "'")
+                    content = content.replace("port='9200'", "port='" + str(es_url.port) + "'")
+                    if es_user != "elastic":
+                        content = content.replace("username='elastic'", "username='" + es_user + "'")
+                    if es_url.scheme.lower() == "https":
+                        content = content.replace("sslmode=''", "sslmode='require'")
+                elif filename.endswith(".password"):
+                    content = content.replace("<REDACTED>", es_pass)
+                else:
+                    continue # shouldn't happen
+
+                with open(os.path.join(TDVT_TDS_DIR, filename), "w") as dest:
+                    dest.write(content)
+
+def latest_tabquery():
+    TABLEAU_INSTALL_FOLDER = os.path.join("C:\\", "Program Files", "Tableau")
+    TABQUERY_UNDERPATH = os.path.join("bin", "tabquerytool.exe")
+
+    latest = ""
+    for (dirpath, dirnames, filenames) in os.walk(TABLEAU_INSTALL_FOLDER, topdown=True):
+        if dirpath != TABLEAU_INSTALL_FOLDER:
+            pass #break
+        for dirname in dirnames:
+            if re.match("^Tableau 202[0-9]\.[0-9]$", dirname):
+                if dirname > latest:
+                    latest = dirname
+    tabquery_path = os.path.join(TABLEAU_INSTALL_FOLDER, latest, TABQUERY_UNDERPATH)
+    os.stat(tabquery_path) # check if the executable's there
+    return tabquery_path
+
+def config_tdvt_override_ini():
+    TDVT_INI_PATH = os.path.join("config", "tdvt", "tdvt_override.ini")
+
+    tabquery_path = latest_tabquery()
+    tabquery_path_line = "TAB_CLI_EXE_X64 = " + tabquery_path
+
+    updated_lines = []
+    with open(TDVT_INI_PATH) as ini:
+        for line in ini.readlines():
+            l = line if not line.startswith("TAB_CLI_EXE_X64") else tabquery_path_line
+            l += '\n'
+            updated_lines.append(l)
+    if len(updated_lines) <= 0:
+        print("WARNING: empty ini file under: " + TDVT_INI_PATH)
+        updated_lines.append("[DEFAULT]\n")
+        updated_lines.append(tabquery_path_line + '\n')
+    with open(TDVT_INI_PATH, "w") as ini:
+        ini.writelines(updated_lines)
+
+def add_data_source():
+    tdvt_args = ["py", "-3", TDVT_LAUNCHER, "action", "--add_ds", "elastic"]
+    interactive = [("connection per tds (standard).", "n"), ("to skip selecting one now:", TDVT_ES_SCHEME),
+            ("Overwrite existing ini file?(y/n)", "y")]
+
+    exe(tdvt_args, interactive)
+
+def config_elastic_ini():
+    ELASTIC_INI = os.path.join("config", "elastic.ini")
+
+    cmdline_override = "CommandLineOverride = -DConnectPluginsPath=%s -DDisableVerifyConnectorPluginSignature=%s" % \
+            (TACO_SRC_DIR, TACO_SIGNED)
+
+    updated_lines = []
+    with open(ELASTIC_INI) as ini:
+        for line in ini.readlines():
+            updated_lines.append(line)
+            if line.startswith("LogicalQueryFormat"):
+                updated_lines.append(cmdline_override)
+    with open(ELASTIC_INI, "w") as ini:
+        ini.writelines(updated_lines)
+
+def run_tdvt():
+    tdvt_args = ["py", "-3", TDVT_LAUNCHER, "run", "elastic"]
+
+    _, stdout, __ = exe(tdvt_args, raise_on_retcode = False)
+    print(stdout)
+
+def parse_args():
+    parser = argparse.ArgumentParser(description="TDVT runner of the Tableau connector for Elasticsearch.",
+            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+    parser.add_argument("-t", "--taco-dir", help="Directory containing the connector file.", 
+            default=TACO_SRC_DIR)
+    parser.add_argument("-s", "--signed", help="Is the .taco signed?", action="store_true", default=TACO_SIGNED)
+    parser.add_argument("-r", "--run-dir", help="Directory to run the testing under.", 
+            default=TDVT_RUN_DIR)
+    parser.add_argument("-u", "--url", help="Elasticsearch URL.", type=str, default=ES_URL)
+    parser.add_argument("-c", "--clean", help="Clean-up run directory", action="store_true", default=False)
+
+    return parser.parse_args()
+
+def main():
+    started_at = time.time()
+
+    args = parse_args()
+
+    cwd = os.getcwd()
+    if args.clean:
+        import shutil # dependency!
+        shutil.rmtree(args.run_dir)
+    if not os.path.isdir(args.run_dir):
+        os.makedirs(args.run_dir)
+    os.chdir(args.run_dir)
+
+    if not os.path.isdir(TDVT_SDK_REPO):
+        checkout_tdvt_sdk()
+    setup_workspace()
+
+    tds_src = TDS_SRC_DIR if os.path.isabs(TDS_SRC_DIR) else os.path.join(cwd, TDS_SRC_DIR)
+    install_tds_files(tds_src, args.url)
+
+    config_tdvt_override_ini()
+    add_data_source()
+    if args.taco_dir != TACO_SRC_DIR and args.signed != TACO_SIGNED:
+        config_elastic_ini()
+
+    run_tdvt()
+
+    print("Test run took %.2f seconds." % (time.time() - started_at))
+
+if __name__ == "__main__":
+    main()
+
+# vim: set noet fenc=utf-8 ff=dos sts=0 sw=4 ts=4 tw=118 expandtab :