Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions packages/cubejs-backend-native/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/cubejs-databricks-jdbc-driver/src/DatabricksQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ export class DatabricksQuery extends BaseQuery {
"'DDD', '@DOY@'), 'Day', 'EEEE'), 'Dy', 'EEE'), 'DD', 'dd'), '@DOY@', 'DDD'), " +
"'AM', 'a'), 'PM', 'a'))";
templates.expressions.timestamp_literal = 'from_utc_timestamp(\'{{ value }}\', \'UTC\')';
// Spark `/` returns DOUBLE for integer operands; `div` returns the integral
// part of the division as BIGINT (truncation toward zero), matching PostgreSQL
templates.expressions.int_division = '({{ left }} div {{ right }})';
templates.expressions.extract = '{% if date_part|lower == "epoch" %}unix_timestamp({{ expr }}){% else %}EXTRACT({{ date_part }} FROM {{ expr }}){% endif %}';
templates.expressions.interval_single_date_part = 'INTERVAL \'{{ num }}\' {{ date_part }}';
templates.quotes.identifiers = '`';
Expand Down
5 changes: 5 additions & 0 deletions packages/cubejs-druid-driver/src/DruidQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export class DruidQuery extends BaseQuery {

// Druid doesn't support ILIKE, so case-insensitive matching is emulated with LOWER(...) LIKE CONCAT(...)
templates.expressions.ilike = 'LOWER({{ expr }}) {% if negated %}NOT {% endif %}LIKE LOWER({{ pattern }})';
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z');
// TIME_PARSE without a pattern parses ISO-8601, which is also Druid's native
// timestamp format. The base template renders the value bare, which is invalid
// syntax
templates.expressions.timestamp_literal = 'TIME_PARSE(\'{{ value }}\')';
delete templates.expressions.like_escape;
templates.filters.like_pattern = 'CONCAT({% if start_wild %}\'%\'{% else %}\'\'{% endif %}, LOWER({{ value }}), {% if end_wild %}\'%\'{% else %}\'\'{% endif %})';
templates.tesseract.ilike = 'LOWER({{ expr }}) {% if negated %}NOT {% endif %}LIKE {{ pattern }}';
Expand Down
4 changes: 4 additions & 0 deletions packages/cubejs-duckdb-driver/src/DuckDBQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export class DuckDBQuery extends BaseQuery {
templates.functions.STRING_AGG = 'STRING_AGG({% if distinct %}DISTINCT {% endif %}{{ args[0] }}, COALESCE({{ args[1] }}, \'\'))';
templates.expressions.like = '{{ expr }} {% if negated %}NOT {% endif %}LIKE {{ pattern }}{% if default_escape %} ESCAPE \'\\\'{% endif %}';
templates.expressions.ilike = '{{ expr }} {% if negated %}NOT {% endif %}ILIKE {{ pattern }}{% if default_escape %} ESCAPE \'\\\'{% endif %}';
// DuckDB `/` performs float division even for integer operands (since v0.8);
// `//` is integer division truncating toward zero (-7 // 2 = -3), matching
// PostgreSQL
templates.expressions.int_division = '({{ left }} // {{ right }})';
return templates;
}

Expand Down
5 changes: 5 additions & 0 deletions packages/cubejs-firebolt-driver/src/FireboltQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export class FireboltQuery extends BaseQuery {

public sqlTemplates() {
const templates = super.sqlTemplates();
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z');
// the TIMESTAMPTZ literal accepts a 'T' separator and the 'Z' UTC designator per
// Firebolt's documented ISO-8601/RFC-3339 grammar. The base template renders the
// value bare, which is invalid syntax
templates.expressions.timestamp_literal = 'TIMESTAMPTZ \'{{ value }}\'';
templates.tesseract.bool_param_cast = 'CAST({{ expr }} AS BOOLEAN)';
return templates;
}
Expand Down
6 changes: 6 additions & 0 deletions packages/cubejs-ksql-driver/src/KsqlQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export class KsqlQuery extends BaseQuery {
// ksqlDB has no `||` string operator — concatenation and LIKE-pattern
// wildcards must use CONCAT (mirrors concatStringsSql / KsqlFilter).
templates.expressions.concat_strings = 'CONCAT({{ strings | join(\', \') }})';
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z').
// ksqlDB silently returns NULL when casting strings with a trailing 'Z'
// (confluentinc/ksql#9094), so the markers are stripped and the UTC zone is passed
// to PARSE_TIMESTAMP explicitly. The base template renders the value bare, which
// is invalid syntax
templates.expressions.timestamp_literal = 'PARSE_TIMESTAMP(\'{{ value | replace("T", " ") | replace("Z", "") }}\', \'yyyy-MM-dd HH:mm:ss.SSS\', \'UTC\')';
templates.filters.like_pattern =
'{% if start_wild or end_wild %}CONCAT(' +
'{% if start_wild %}\'%\', {% endif %}{{ value }}{% if end_wild %}, \'%\'{% endif %})' +
Expand Down
6 changes: 6 additions & 0 deletions packages/cubejs-pinot-driver/src/PinotQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ export class PinotQuery extends BaseQuery {
'{% if limit is not none %}\nLIMIT {{ limit }}{% endif %}' +
'{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}';
templates.expressions.extract = 'EXTRACT({{ date_part }} FROM {{ expr }})';
// Pinot `/` returns DOUBLE for integer operands, and intDiv() is floor
// division (intDiv(-7, 2) = -4). CAST to LONG truncates toward zero
// (CAST(-7 / 2 AS LONG) = -3), matching PostgreSQL integer division.
// Note: the division itself happens in DOUBLE, so results are exact only
// up to 2^53
templates.expressions.int_division = 'CAST({{ left }} / {{ right }} AS LONG)';
templates.expressions.timestamp_literal = 'fromDateTime(\'{{ value }}\', \'yyyy-MM-dd\'\'T\'\'HH:mm:ss.SSS\'\'Z\'\'\')';
// NOTE: this template contains a comma; two order expressions are being generated
templates.expressions.sort = '{{ expr }} IS NULL {% if nulls_first %}DESC{% else %}ASC{% endif %}, {{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}';
Expand Down
9 changes: 8 additions & 1 deletion packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -4609,6 +4609,10 @@ export class BaseQuery {
case: 'CASE{% if expr %} {{ expr }}{% endif %}{% for when, then in when_then %} WHEN {{ when }} THEN {{ then }}{% endfor %}{% if else_expr %} ELSE {{ else_expr }}{% endif %} END',
is_null: '({{ expr }} IS {% if negate %}NOT {% endif %}NULL)',
binary: '({{ left }} {{ op }} {{ right }})',
// Integer division with PostgreSQL semantics: truncation toward zero.
// Plain `/` is correct for dialects where int / int is integer division;
// dialects with decimal or float `/` must override this template
int_division: '({{ left }} / {{ right }})',
sort: '{{ expr }} {% if asc %}ASC{% else %}DESC{% endif %} NULLS {% if nulls_first %}FIRST{% else %}LAST{% endif %}',
order_by: '{% if index %} {{ index }} {% else %} {{ expr }} {% endif %} {% if asc %}ASC{% else %}DESC{% endif %}{% if nulls_first %} NULLS FIRST{% endif %}',
cast: 'CAST({{ expr }} AS {{ data_type }})',
Expand All @@ -4633,7 +4637,10 @@ export class BaseQuery {
wrap_segment_select: '{{ expr }}',
wrap_segment_filter: '{{ expr }}',
rolling_window_expr_timestamp_cast: '{{ value }}',
timestamp_literal: '{{ value }}',
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z').
// ANSI CAST of the quoted value is the most portable default; dialects override
// with their exact parsing construct. A bare unquoted value is never valid SQL
timestamp_literal: 'CAST(\'{{ value }}\' AS TIMESTAMP)',
between: '{{ expr }} {% if negated %}NOT {% endif %}BETWEEN {{ low }} AND {{ high }}',
},
tesseract: {
Expand Down
3 changes: 3 additions & 0 deletions packages/cubejs-schema-compiler/src/adapter/BigqueryQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ export class BigqueryQuery extends BaseQuery {
delete templates.functions.PERCENTILECONT;
templates.expressions.binary = '{% if op == \'%\' %}MOD({{ left }}, {{ right }}){% else %}({{ left }} {{ op }} {{ right }}){% endif %}';
templates.expressions.interval = 'INTERVAL {{ interval }}';
// BigQuery `/` on INT64 operands returns FLOAT64; DIV() is integer division
// truncating toward zero, matching PostgreSQL (DIV(12, -7) = -1)
templates.expressions.int_division = 'DIV({{ left }}, {{ right }})';
templates.expressions.extract = 'EXTRACT({% if date_part == \'DOW\' %}DAYOFWEEK{% elif date_part == \'DOY\' %}DAYOFYEAR{% else %}{{ date_part }}{% endif %} FROM {{ expr }})';
templates.expressions.timestamp_literal = 'TIMESTAMP(\'{{ value }}\')';
templates.expressions.rolling_window_expr_timestamp_cast = 'TIMESTAMP({{ value }})';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ export class ClickHouseQuery extends BaseQuery {
delete templates.types.interval;
delete templates.types.binary;
templates.expressions.is_not_distinct_from = 'isNotDistinctFrom({{ left }}, {{ right }})';
// ClickHouse `/` always returns Float64; intDiv is integer division truncating
// toward zero, matching PostgreSQL (intDiv(-7, 2) = -3 despite docs saying
// "rounded down")
templates.expressions.int_division = 'intDiv({{ left }}, {{ right }})';

templates.statements.time_series_select = 'SELECT parseDateTimeBestEffort(dates.f) date_from, parseDateTimeBestEffort(dates.t) date_to \n' +
'FROM (\n' +
Expand Down
5 changes: 5 additions & 0 deletions packages/cubejs-schema-compiler/src/adapter/MssqlQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ export class MssqlQuery extends BaseQuery {
templates.expressions.concat_strings = '{{ strings | join(\' + \' ) }}';
// NOTE: this template contains a comma; two order expressions are being generated
templates.expressions.sort = '{{ expr }} IS NULL {% if nulls_first %}DESC{% else %}ASC{% endif %}, {{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}';
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z');
// CONVERT style 127 is defined as exactly this format (yyyy-mm-ddThh:mi:ss.mmmZ,
// "ISO8601 with time zone Z"). The base template renders the value bare, which is
// invalid T-SQL syntax
templates.expressions.timestamp_literal = 'CONVERT(DATETIME2, \'{{ value }}\', 127)';
templates.types.string = 'VARCHAR';
templates.types.boolean = 'BIT';
templates.types.integer = 'INT';
Expand Down
9 changes: 9 additions & 0 deletions packages/cubejs-schema-compiler/src/adapter/MysqlQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ export class MysqlQuery extends BaseQuery {
templates.quotes.escape = '\\`';
// NOTE: this template contains a comma; two order expressions are being generated
templates.expressions.sort = '{{ expr }} IS NULL {% if nulls_first %}DESC{% else %}ASC{% endif %}, {{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}';
// MySQL `/` returns DECIMAL even for integer operands; DIV discards the
// fractional part (truncation toward zero), matching PostgreSQL (-5 DIV 2 = -2)
templates.expressions.int_division = '({{ left }} DIV {{ right }})';
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z').
// MySQL parses the 'T'/'Z' markers only with a "Truncated incorrect datetime value"
// warning and ignores the zone, so both markers are stripped instead. The driver
// pins the session time zone to UTC, which keeps the naive literal on the same
// instant. The base template renders the value bare, which is invalid MySQL syntax
templates.expressions.timestamp_literal = 'TIMESTAMP(\'{{ value | replace("T", " ") | replace("Z", "") }}\')';
delete templates.expressions.ilike;
templates.types.string = 'CHAR';
templates.types.boolean = 'TINYINT';
Expand Down
7 changes: 7 additions & 0 deletions packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ export class OracleQuery extends BaseQuery {
templates.functions.UTCTIMESTAMP = 'SYS_EXTRACT_UTC(SYSTIMESTAMP)';
// Oracle forbids `AS` before a table/subquery alias.
templates.expressions.query_aliased = '{{ query }} {{ quoted_alias }}';
// Oracle `/` on NUMBER keeps the fractional part; TRUNC drops decimal digits
// (truncation toward zero), matching PostgreSQL integer division
templates.expressions.int_division = 'TRUNC({{ left }} / {{ right }})';
// Timestamp constants arrive as ISO-8601 UTC strings ('2021-01-01T00:00:00.000Z');
// the 'T'/'Z' markers are consumed as literal chunks in the format mask. The base
// template renders the value bare, which is invalid Oracle syntax
templates.expressions.timestamp_literal = 'TO_TIMESTAMP(\'{{ value }}\', \'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"\')';
// Oracle does not support positional GROUP BY — group by expressions.
templates.statements.group_by_exprs = '{{ group_by | map(attribute=\'expr\') | join(\', \') }}';
// No `AS` before the FROM subquery alias, and Oracle row-limiting syntax.
Expand Down
4 changes: 4 additions & 0 deletions packages/cubejs-schema-compiler/src/adapter/SnowflakeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ export class SnowflakeQuery extends BaseQuery {
templates.functions.BTRIM = 'TRIM({{ args_concat }})';
templates.functions.STRING_AGG = 'LISTAGG({% if distinct %}DISTINCT {% endif %}{{ args_concat }})';
templates.expressions.extract = 'EXTRACT({{ date_part }} FROM {{ expr }})';
// Snowflake `/` is decimal division even for integer operands (output scale
// is dividend scale + 6), while this template must keep PostgreSQL integer
// division semantics. TRUNC rounds toward zero, matching PostgreSQL.
templates.expressions.int_division = 'CAST(TRUNC({{ left }} / {{ right }}) AS BIGINT)';
// Snowflake can't EXTRACT(EPOCH FROM <interval>), so the epoch of a timestamp
// difference (left - right) is rendered as fractional seconds between them.
// TIMESTAMPDIFF is measured once at microsecond granularity (no per-second
Expand Down
16 changes: 8 additions & 8 deletions rust/cubesql/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/cubesql/cubesql/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ homepage = "https://cube.dev"

[dependencies]
arc-swap = "1"
datafusion = { git = 'https://github.com/cube-js/arrow-datafusion.git', rev = "b01223b6454b0d72154d15a88aec76efc9da726d", default-features = false, features = [
datafusion = { git = 'https://github.com/cube-js/arrow-datafusion.git', rev = "d203d8771a9673fb676b44dce1f99e91634b4080", default-features = false, features = [
"regex_expressions",
"unicode_expressions",
] }
Expand Down
Loading
Loading