Skip to content

Commit 230fce9

Browse files
waralexrommarianore-muttdata
authored andcommitted
feat(tesseract): Initial BigQuery support (cube-js#9577)
1 parent 5fdc290 commit 230fce9

File tree

34 files changed

+264
-147
lines changed

34 files changed

+264
-147
lines changed

.github/workflows/drivers-tests.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,19 @@ on:
5757
# To test SQL API Push down
5858
- 'packages/cubejs-backend-native/**'
5959
- 'rust/cubesql/**'
60+
workflow_dispatch:
61+
inputs:
62+
use_tesseract_sql_planner:
63+
description: 'Enable TESSERACT_SQL_PLANNER?'
64+
required: true
65+
default: 'false'
66+
type: choice
67+
options:
68+
- 'true'
69+
- 'false'
6070

6171
env:
62-
CUBEJS_TESSERACT_ORCHESTRATOR: true
72+
USE_TESSERACT_SQL_PLANNER: false
6373

6474
jobs:
6575
latest-tag-sha:
@@ -316,6 +326,8 @@ jobs:
316326
(contains(env.CLOUD_DATABASES, matrix.database) && env.DRIVERS_TESTS_ATHENA_CUBEJS_AWS_KEY != '') ||
317327
(!contains(env.CLOUD_DATABASES, matrix.database))
318328
env:
329+
DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.use_tesseract_sql_planner || env.USE_TESSERACT_SQL_PLANNER }}
330+
319331
# Athena
320332
DRIVERS_TESTS_ATHENA_CUBEJS_AWS_KEY: ${{ secrets.DRIVERS_TESTS_ATHENA_CUBEJS_AWS_KEY }}
321333
DRIVERS_TESTS_ATHENA_CUBEJS_AWS_SECRET: ${{ secrets.DRIVERS_TESTS_ATHENA_CUBEJS_AWS_SECRET }}

packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ export class BaseQuery {
330330
this.customSubQueryJoins = this.options.subqueryJoins ?? [];
331331
this.useNativeSqlPlanner = this.options.useNativeSqlPlanner ?? getEnv('nativeSqlPlanner');
332332
this.canUseNativeSqlPlannerPreAggregation = false;
333-
if (this.useNativeSqlPlanner) {
333+
if (this.useNativeSqlPlanner && !this.neverUseSqlPlannerPreaggregation()) {
334334
const hasMultiStageMeasures = this.fullKeyQueryAggregateMeasures({ hasMultipliedForPreAggregation: true }).multiStageMembers.length > 0;
335335
this.canUseNativeSqlPlannerPreAggregation = hasMultiStageMeasures;
336336
}
@@ -348,6 +348,11 @@ export class BaseQuery {
348348
this.initUngrouped();
349349
}
350350

351+
// Temporary workaround to avoid checking for multistage in CubeStoreQuery, since that could lead to errors when HLL functions are present in the query.
352+
neverUseSqlPlannerPreaggregation() {
353+
return false;
354+
}
355+
351356
prebuildJoin() {
352357
try {
353358
// TODO allJoinHints should contain join hints form pre-agg
@@ -774,7 +779,6 @@ export class BaseQuery {
774779
R.map((hash) => ((!hash || !hash.id) ? null : hash)),
775780
R.reject(R.isNil),
776781
)(this.options.order);
777-
778782
const queryParams = {
779783
measures: this.options.measures,
780784
dimensions: this.options.dimensions,
@@ -791,7 +795,8 @@ export class BaseQuery {
791795
baseTools: this,
792796
ungrouped: this.options.ungrouped,
793797
exportAnnotatedSql: exportAnnotatedSql === true,
794-
preAggregationQuery: this.options.preAggregationQuery
798+
preAggregationQuery: this.options.preAggregationQuery,
799+
totalQuery: this.options.totalQuery,
795800
};
796801

797802
const buildResult = nativeBuildSqlAndParams(queryParams);
@@ -870,12 +875,12 @@ export class BaseQuery {
870875

871876
// FIXME helper for native generator, maybe should be moved entirely to rust
872877
generateTimeSeries(granularity, dateRange) {
873-
return timeSeriesBase(granularity, dateRange);
878+
return timeSeriesBase(granularity, dateRange, { timestampPrecision: this.timestampPrecision() });
874879
}
875880

876881
// FIXME helper for native generator, maybe should be moved entirely to rust
877882
generateCustomTimeSeries(granularityInterval, dateRange, origin) {
878-
return timeSeriesFromCustomInterval(granularityInterval, dateRange, moment(origin), { timestampPrecision: 3 });
883+
return timeSeriesFromCustomInterval(granularityInterval, dateRange, moment(origin), { timestampPrecision: this.timestampPrecision() });
879884
}
880885

881886
getPreAggregationByName(cube, preAggregationName) {
@@ -3869,6 +3874,9 @@ export class BaseQuery {
38693874
like_escape: '{{ like_expr }} ESCAPE {{ escape_char }}',
38703875
concat_strings: '{{ strings | join(\' || \' ) }}',
38713876
},
3877+
tesseract: {
3878+
ilike: '{{ expr }} {% if negated %}NOT {% endif %}ILIKE {{ pattern }}', // May require different overloads in Tesseract than the ilike from expressions used in SQLAPI.
3879+
},
38723880
filters: {
38733881
equals: '{{ column }} = {{ value }}{{ is_null_check }}',
38743882
not_equals: '{{ column }} <> {{ value }}{{ is_null_check }}',

packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,24 @@ export class BigqueryQuery extends BaseQuery {
261261
templates.expressions.timestamp_literal = 'TIMESTAMP(\'{{ value }}\')';
262262
delete templates.expressions.ilike;
263263
delete templates.expressions.like_escape;
264+
templates.filters.like_pattern = 'CONCAT({% if start_wild %}\'%\'{% else %}\'\'{% endif %}, LOWER({{ value }}), {% if end_wild %}\'%\'{% else %}\'\'{% endif %})';
265+
templates.tesseract.ilike = 'LOWER({{ expr }}) {% if negated %}NOT {% endif %} LIKE {{ pattern }}';
264266
templates.types.boolean = 'BOOL';
265267
templates.types.float = 'FLOAT64';
266268
templates.types.double = 'FLOAT64';
267269
templates.types.decimal = 'BIGDECIMAL({{ precision }},{{ scale }})';
268270
templates.types.binary = 'BYTES';
271+
templates.expressions.cast_to_string = 'CAST({{ expr }} AS STRING)';
269272
templates.operators.is_not_distinct_from = 'IS NOT DISTINCT FROM';
270273
templates.join_types.full = 'FULL';
274+
templates.statements.time_series_select = 'SELECT DATETIME(TIMESTAMP(f)) date_from, DATETIME(TIMESTAMP(t)) date_to \n' +
275+
'FROM (\n' +
276+
'{% for time_item in seria %}' +
277+
' select \'{{ time_item[0] }}\' f, \'{{ time_item[1] }}\' t \n' +
278+
'{% if not loop.last %} UNION ALL\n{% endif %}' +
279+
'{% endfor %}' +
280+
') AS dates';
281+
271282
return templates;
272283
}
273284
}

packages/cubejs-schema-compiler/src/adapter/CubeStoreQuery.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export class CubeStoreQuery extends BaseQuery {
6868
return `date_trunc('${GRANULARITY_TO_INTERVAL[granularity]}', ${dimension})`;
6969
}
7070

71+
// Temporary workaround to avoid checking for multistage in CubeStoreQuery, since that could lead to errors when HLL functions are present in the query.
72+
public neverUseSqlPlannerPreaggregation() {
73+
return true;
74+
}
75+
7176
/**
7277
* Returns sql for source expression floored to timestamps aligned with
7378
* intervals relative to origin timestamp point.

packages/cubejs-testing-drivers/fixtures/athena.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"CUBEJS_PG_SQL_PORT": "5656",
1616
"CUBEJS_SQL_USER": "admin",
1717
"CUBEJS_SQL_PASSWORD": "admin_password",
18-
"CUBESQL_SQL_PUSH_DOWN": "true"
18+
"CUBESQL_SQL_PUSH_DOWN": "true",
19+
"CUBEJS_TESSERACT_SQL_PLANNER": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}"
1920
},
2021
"ports" : ["4000", "5656"]
2122
},

packages/cubejs-testing-drivers/fixtures/bigquery.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"CUBESQL_SQL_PUSH_DOWN": "true",
1818

1919
"CUBEJS_DB_EXPORT_BUCKET": "cube-open-source-export-bucket",
20-
"CUBEJS_DB_EXPORT_BUCKET_TYPE": "gcp"
20+
"CUBEJS_DB_EXPORT_BUCKET_TYPE": "gcp",
21+
"CUBEJS_TESSERACT_SQL_PLANNER": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}"
2122
},
2223
"ports" : ["4000", "5656"]
2324
},

packages/cubejs-testing-drivers/fixtures/clickhouse.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"CUBEJS_PG_SQL_PORT": "5656",
2626
"CUBEJS_SQL_USER": "admin",
2727
"CUBEJS_SQL_PASSWORD": "admin_password",
28-
"CUBESQL_SQL_PUSH_DOWN": "true"
28+
"CUBESQL_SQL_PUSH_DOWN": "true",
29+
"CUBEJS_TESSERACT_SQL_PLANNER": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}"
2930
},
3031
"depends_on": ["data"],
3132
"links": ["data"],

packages/cubejs-testing-drivers/fixtures/databricks-jdbc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@
7373
"CUBEJS_PG_SQL_PORT": "5656",
7474
"CUBEJS_SQL_USER": "admin",
7575
"CUBEJS_SQL_PASSWORD": "admin_password",
76-
"CUBESQL_SQL_PUSH_DOWN": "true"
76+
"CUBESQL_SQL_PUSH_DOWN": "true",
77+
"CUBEJS_TESSERACT_SQL_PLANNER": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}"
7778
},
7879
"ports" : ["4000", "5656"]
7980
},

packages/cubejs-testing-drivers/fixtures/mssql.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"CUBEJS_PG_SQL_PORT": "5656",
1212
"CUBEJS_SQL_USER": "admin",
1313
"CUBEJS_SQL_PASSWORD": "admin_password",
14-
"CUBESQL_SQL_PUSH_DOWN": "true"
14+
"CUBESQL_SQL_PUSH_DOWN": "true",
15+
"CUBEJS_TESSERACT_SQL_PLANNER": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}"
1516
},
1617
"depends_on": ["data"],
1718
"links": ["data"],

packages/cubejs-testing-drivers/fixtures/mysql.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"CUBEJS_PG_SQL_PORT": "5656",
1313
"CUBEJS_SQL_USER": "admin",
1414
"CUBEJS_SQL_PASSWORD": "admin_password",
15-
"CUBESQL_SQL_PUSH_DOWN": "true"
15+
"CUBESQL_SQL_PUSH_DOWN": "true",
16+
"CUBEJS_TESSERACT_SQL_PLANNER": "${DRIVERS_TESTS_CUBEJS_TESSERACT_SQL_PLANNER}"
1617
},
1718
"depends_on": ["data"],
1819
"links": ["data"],

0 commit comments

Comments
 (0)