cube-js / cube-js/cube

MSSQL SQL API pushdown emits invalid null ordering and reports a FETCH NEXT error

Closed Beginner friendly
#11,775 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
20.8k
Forks
2.1k
Avg merge
1d 2h
Merged PRs (30d)
181

Description

## Describe the bug

The MSSQL `expressions.sort` template generates `ORDER BY IS NULL ...` to emulate PostgreSQL null ordering. SQL Server cannot use a predicate as a sort expression. When the query also has OFFSET/FETCH, the driver reports `Invalid usage of the option NEXT in the FETCH statement.` The earlier error in `precedingErrors` is `Incorrect syntax near the keyword 'IS'.`

Regular semantic queries can succeed because they use a different ordering template. SQL API queries that enter the pushdown path encounter this defect.

## Reproduction

Run this on SQL Server or Azure SQL:

```sql
SELECT x
FROM (VALUES (CAST(NULL AS int)), (1), (2)) AS t(x)
ORDER BY x IS NULL ASC, x ASC
OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
```

Expected order for ASC NULLS LAST: `1, 2, NULL`.

Actual result: syntax error near `IS`, followed by the FETCH NEXT error.

The same pagination succeeds when the null discriminator is a scalar:

```sql
SELECT x
FROM (VALUES (CAST(NULL AS int)), (1), (2)) AS t(x)
ORDER BY CASE WHEN x IS NULL THEN 1 ELSE 0 END ASC, x ASC
OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
```

To inspect the responsible template in the published Cube package:

```javascript
const { MssqlQuery } = require('@cubejs-backend/schema-compiler');
const query = Object.create(MssqlQuery.prototype);
console.log(query.sqlTemplates().expressions.sort);
```

It returns:

```jinja
{{ expr }} IS NULL {% if nulls_first %}DESC{% else %}ASC{% endif %}, {{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}
```

## Expected behavior and proposed fix

Wrap the null predicate in `CASE WHEN ... THEN 1 ELSE 0 END`. Keep the discriminator direction controlled by `nulls_first`, independently of the value direction controlled by `asc`.

```jinja
CASE WHEN {{ expr }} IS NULL THEN 1 ELSE 0 END {% if nulls_first %}DESC{% else %}ASC{% endif %}, {{ expr }} {% if asc %}ASC{% else %}DESC{% endif %}
```

This preserves ASC/DESC and NULLS FIRST/LAST while generating valid T-SQL. No pagination or planner changes are needed.

## Versions and scope

- Reproduced with `cubejs/cube:v1.7.33`.
- Azure SQL reports `Microsoft SQL Azure 12.0.2000.8`, database compatibility level 150.

## Related reports

A search of open and closed Cube issues and pull requests on 2026-09-05 found no exact duplicate. [#7392](https://github.com/cube-js/cube/issues/7392) also concerns MSSQL pagination, but its generated SQL lacks ORDER BY; it is a different failure. MSSQL support work in [#10343](https://github.com/cube-js/cube/pull/10343) is related background.

The independent missing-join template defect and numeric literal precision issue are outside this patch.

Contributor guide

Open the contributing guide

Research direction

Start by inspecting MssqlQuery.prototype.sqlTemplates().expressions.sort in the published @cubejs-backend/schema-compiler package, then run the provided SQL Server or Azure SQL reproduction. Done means the template emits a scalar CASE null discriminator and preserves independent NULLS FIRST/LAST and ASC/DESC ordering with OFFSET/FETCH.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, sql
Domain
api, databases
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.