Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix(schema-compiler): add support for time filters and rolling windows and fix subquery aliasing in oracle #10066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Tankilevitch wants to merge 3 commits into cube-js:master
base: master
Choose a base branch
Loading
from Tankilevitch:fix/oracle-subquery-as-syntax

Conversation

@Tankilevitch
Copy link
Contributor

@Tankilevitch Tankilevitch commented Oct 19, 2025
edited
Loading

Fix Oracle Query Generation Issues

Summary

This PR fixes three critical Oracle database compatibility issues that prevented queries with rolling windows, time dimension filters, and subqueries from executing. All fixes maintain backward compatibility with other database adapters.


Issue #1: Invalid AS Keyword in Subquery Aliases

Problem

Oracle does not support the AS keyword before table/subquery aliases. Queries requiring subqueries would fail with:

ORA-00933: SQL command not properly ended

Why It Happened

The query builder was hardcoding the as keyword when generating subquery aliases, which works for PostgreSQL/MySQL but is invalid in Oracle SQL syntax.

What We Did

Modified the query builder to use a database-specific property (asSyntaxJoin) that each adapter can override. Oracle sets this to an empty string, while other databases use "AS".

Example

PostgreSQL (unchanged):

FROM (SELECT ...) AS q_0
INNER JOIN (SELECT ...) AS q_1 ON ...

Oracle (fixed):

FROM (SELECT ...) q_0
INNER JOIN (SELECT ...) q_1 ON ...

Issue #2: TypeError on Time Dimensions Without Granularity

Problem

When using time dimensions for filtering only (without specifying granularity), queries would crash with:

TypeError: Cannot read properties of undefined (reading 'isNaturalAligned')

Example Query

{
 "measures": ["visitors.count"],
 "timeDimensions": [{
 "dimension": "visitors.createdAt",
 "dateRange": ["2020年01月01日", "2020年12月31日"]
 // No granularity - just filtering
 }]
}

Why It Happened

The code assumed granularity was always present and tried to access properties on an undefined object. Time dimensions used only for filtering don't require granularity.

What We Did

Added a null check before accessing granularity properties. When granularity is not specified, the dimension is used as-is for filtering without grouping.

Result

-- Query now generates correctly:
SELECT count(*) FROM visitors
WHERE created_at >= to_date(...) AND created_at <= to_date(...)
-- No GROUP BY (correct for filtering without granularity)

Issue #3: Invalid Interval Syntax for Oracle

Problem

Queries with rolling windows would fail with:

ORA-17041: Missing IN or OUT parameter at index: 1

Example Query

{
 "measures": ["visitors.unboundedCount"],
 "timeDimensions": [{
 "dimension": "visitors.createdAt",
 "granularity": "year",
 "dateRange": ["2020年01月01日", "2022年12月31日"]
 }]
}

(where unboundedCount has a rollingWindow configuration)

Why It Happened

The default date arithmetic used PostgreSQL-style interval syntax:

-- PostgreSQL syntax (doesn't work in Oracle)
date_field >= some_date - interval '1 year'

Oracle requires specific functions for date arithmetic instead of the INTERVAL keyword.

What We Did

Implemented Oracle-specific addInterval and subtractInterval methods that use:

  • ADD_MONTHS(date, n) for year/month/quarter intervals
  • NUMTODSINTERVAL(n, unit) for day/hour/minute/second intervals

Transformation Examples

Before (PostgreSQL syntax):

WHERE date_field >= to_date(:"?", ...) - interval '1 year'

After (Oracle syntax):

WHERE date_field >= ADD_MONTHS(to_date(:"?", ...), -12)

Interval Conversion

Interval Type Oracle Function
Years ADD_MONTHS(date, ±12)
Quarters ADD_MONTHS(date, ±3)
Months ADD_MONTHS(date, ±1)
Days date ± NUMTODSINTERVAL(n, 'DAY')
Hours date ± NUMTODSINTERVAL(n, 'HOUR')

Testing

New Test Coverage

Created comprehensive test suite in oracle-query.test.ts with 10 tests covering:

  • Basic query generation
  • Subquery aliases without AS keyword (multiple scenarios)
  • FETCH NEXT syntax instead of LIMIT
  • Group by dimensions (not indexes)
  • Time dimensions without granularity
  • Oracle-specific interval arithmetic

Regression Protection

Added test in postgres-query.test.ts to ensure PostgreSQL continues using AS keyword correctly.


Backward Compatibility

All changes are backward compatible:

  • PostgreSQL, MySQL, BigQuery, etc. continue using AS keyword
  • The granularity null check works for all database adapters
  • Only Oracle uses the new interval arithmetic methods
  • All existing queries continue to work as before

Impact

These fixes enable Oracle users to:

  • Use time dimensions for filtering without specifying granularity
  • Execute queries with rolling windows (trailing, leading, offset)
  • Perform time-based comparisons with proper date arithmetic
  • Use any query pattern that requires subqueries or date calculations

... for Oracle compatibility
Oracle database does not support the AS keyword for table/subquery aliasing,
while other databases like PostgreSQL and MySQL do. The existing BaseQuery
implementation hardcoded 'as' in subquery alias generation, causing Oracle
queries to fail.
This change:
- Replaces hardcoded 'as' with asSyntaxJoin property in BaseQuery
- Oracle returns empty string for asSyntaxJoin (no AS keyword)
- PostgreSQL/MySQL return 'AS' (maintains existing behavior)
- Adds comprehensive Oracle query test suite validating AS syntax removal
- Adds PostgreSQL regression test ensuring AS keyword is still present
This fixes queries with rolling windows and multiple subqueries on Oracle,
which previously generated invalid SQL like:
 SELECT ... FROM (...) as q_0 INNER JOIN (...) as q_1 ON ...
Now Oracle correctly generates:
 SELECT ... FROM (...) q_0 INNER JOIN (...) q_1 ON ...
@Tankilevitch Tankilevitch requested a review from a team as a code owner October 19, 2025 14:31
@github-actions github-actions bot added javascript Pull requests that update Javascript code pr:community Contribution from Cube.js community members. labels Oct 19, 2025
- Fix AS keyword in subquery aliases (Oracle doesn't support it)
- Handle time dimensions without granularity to prevent TypeError
- Implement Oracle-specific interval arithmetic using ADD_MONTHS and NUMTODSINTERVAL
- Add comprehensive test suite for Oracle query generation
These changes enable Oracle users to execute queries with:
- Time dimension filters without granularity specification
- Rolling windows and time-based calculations
- Multiple subqueries with proper aliasing
All changes maintain backward compatibility with other database adapters.
@Tankilevitch Tankilevitch changed the title (削除) fix(schema-compiler): remove hardcoded AS keyword in subquery aliases for Oracle compatibility (削除ここまで) (追記) fix(schema-compiler): add support for time filters and rolling windows and fix subquery aliasing in oracle (追記ここまで) Oct 19, 2025
@KSDaemon KSDaemon self-assigned this Oct 21, 2025
Copy link
Member

@Tankilevitch thank you for the fix! I'll review it a bit later.
In the meantime, as I merged your previous fix, please rebase and resolve the conflicts in the tests :)

expect(sql).toMatch(/\s+AS\s+q_0\s+/);

// Should NOT have pattern ) q_0 (without AS)
// This regex checks for closing paren followed by space(s), q_0, space, but NOT preceded by AS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the comment is not aligned with the regex as it doesn't include parentheses.

*/
dimensionTimeGroupedColumn(dimension, granularity) {
// Handle case when granularity is not specified (e.g., time dimension used only for filtering)
if (!granularity) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you show the example when this function is called without granularity object?

@KSDaemon KSDaemon added the driver:oracle Issues relating to the Oracle driver label Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@KSDaemon KSDaemon KSDaemon left review comments

Labels

driver:oracle Issues relating to the Oracle driver javascript Pull requests that update Javascript code pr:community Contribution from Cube.js community members.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /