Skip to content

Tesseract planner generates empty FROM clause for Pinot sql_table cubes #10988

@seanm-stripe

Description

@seanm-stripe

Describe the bug
When CUBEJS_TESSERACT_SQL_PLANNER=true, Pinot-backed cubes can generate invalid SQL with an empty FROM subquery:

FROM (

) AS

This appears to be caused by PinotQuery.sqlTemplates() overriding statements.select with a template that reads {{ from }} / {{ from_alias }}, while the Tesseract planner passes the source through from_prepared. The base query template handles from_prepared, but the Pinot override does not.

To Reproduce
Steps to reproduce the behavior:

  1. Configure a Cube project with the Pinot driver.
  2. Define a cube using sql_table.
  3. Enable Tesseract with CUBEJS_TESSERACT_SQL_PLANNER=true.
  4. Generate SQL for a query against the Pinot cube.
  5. Observe that the generated SQL contains an empty FROM ( ) AS clause.

Example generated SQL shape:

SELECT
  "events".id "events__id",
  sum("events".amount) "events__total_amount"
FROM (

) AS
GROUP BY 1

Expected behavior
The generated SQL should include the Pinot table reference from sql_table, for example:

SELECT
  "events".id "events__id",
  sum("events".amount) "events__total_amount"
FROM events AS "events"
GROUP BY 1

More generally, Pinot’s statements.select template should support the same Tesseract-facing variables as the base select template, including from_prepared.

Screenshots
NA

Minimally reproducible Cube Schema
In case your bug report is data modelling related please put your minimally reproducible Cube Schema here.
You can use selects without tables in order to achieve that as follows.

cube(`Events`, {
  sql_table: `events`,

  measures: {
    totalAmount: {
      sql: `amount`,
      type: `sum`,
    },
  },

  dimensions: {
    id: {
      sql: `id`,
      type: `number`,
      primary_key: true,
    },
  },
});

Version:
Observed on Cube 1.6.52.

Additional context
The likely source is packages/cubejs-pinot-driver/src/PinotQuery.ts.

PinotQuery.sqlTemplates() currently overrides templates.statements.select and references {{ from }}:

templates.statements.select = 'SELECT ... \n' +
  'FROM (\n  {{ from }}\n) AS {{ from_alias }} \n' +
  ...

However, Tesseract renders select statements with from_prepared:

context! {
  from_prepared => from,
  ...
}

The base BaseQuery select template handles this via:

{% if from %}
FROM (
{{ from | indent(2, true) }}
) AS {{ from_alias }}{% elif from_prepared %}
FROM {{ from_prepared }}
{% endif %}

Pinot’s override likely needs to preserve that branch. It may also need to preserve other base-template variables used by Tesseract, such as ctes, distinct, joins, filter, and having.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions