Skip to content
Open
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
6 changes: 3 additions & 3 deletions packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -1380,8 +1380,8 @@ export class BaseQuery {
const join = R.drop(1, toJoin)
.map(
(q, i) => (this.dimensionAliasNames().length ?
`INNER JOIN ${this.wrapInParenthesis((q))} as q_${i + 1} ON ${this.dimensionsJoinCondition(`q_${i}`, `q_${i + 1}`)}` :
`, ${this.wrapInParenthesis(q)} as q_${i + 1}`),
`INNER JOIN ${this.wrapInParenthesis((q))} ${this.asSyntaxJoin} q_${i + 1} ON ${this.dimensionsJoinCondition(`q_${i}`, `q_${i + 1}`)}` :
`, ${this.wrapInParenthesis(q)} ${this.asSyntaxJoin} q_${i + 1}`),
).join('\n');

const columnsToSelect = this.evaluateSymbolSqlWithContext(
Expand Down Expand Up @@ -1410,7 +1410,7 @@ export class BaseQuery {
return `${toJoin[0].replace(/^SELECT/, `SELECT ${this.topLimit()}`)} ${this.orderBy()}${this.groupByDimensionLimit()}`;
}

return `SELECT ${this.topLimit()}${columnsToSelect} FROM ${this.wrapInParenthesis(toJoin[0])} as q_0 ${join}${havingFilters}${this.orderBy()}${this.groupByDimensionLimit()}`;
return `SELECT ${this.topLimit()}${columnsToSelect} FROM ${this.wrapInParenthesis(toJoin[0])} ${this.asSyntaxJoin} q_0 ${join}${havingFilters}${this.orderBy()}${this.groupByDimensionLimit()}`;
}

wrapInParenthesis(select) {
Expand Down
91 changes: 89 additions & 2 deletions packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { parseSqlInterval } from '@cubejs-backend/shared';
import { BaseQuery } from './BaseQuery';
import { BaseFilter } from './BaseFilter';
import { UserError } from '../compiler/UserError';
import { BaseDimension } from './BaseDimension';
import type { BaseDimension } from './BaseDimension';

const GRANULARITY_VALUE = {
day: 'DD',
Expand Down Expand Up @@ -55,7 +56,11 @@ export class OracleQuery extends BaseQuery {
* using forSelect dimensions for grouping
*/
public groupByClause() {
const dimensions = this.forSelect().filter((item: any) => !!item.dimension) as BaseDimension[];
// Only include dimensions that have select columns
// Time dimensions without granularity return null from selectColumns()
const dimensions = this.forSelect().filter((item: any) => (
!!item.dimension && item.selectColumns && item.selectColumns()
)) as BaseDimension[];
Comment on lines +59 to +63
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Following up on your comment about when we should check !granularity in BaseQuery. I’ve decided, for now, to align its behavior with how PostgresQuery handles grouping column selection.

if (!dimensions.length) {
return '';
}
Expand Down Expand Up @@ -92,6 +97,88 @@ export class OracleQuery extends BaseQuery {
return `TRUNC(${dimension}, '${GRANULARITY_VALUE[granularity]}')`;
}

/**
* Oracle uses ADD_MONTHS for year/month/quarter intervals
* and NUMTODSINTERVAL for day/hour/minute/second intervals
*/
public addInterval(date: string, interval: string): string {
const intervalParsed = parseSqlInterval(interval);
let res = date;

// Handle year/month/quarter using ADD_MONTHS
let totalMonths = 0;
if (intervalParsed.year) {
totalMonths += intervalParsed.year * 12;
}
if (intervalParsed.quarter) {
totalMonths += intervalParsed.quarter * 3;
}
if (intervalParsed.month) {
totalMonths += intervalParsed.month;
}

if (totalMonths !== 0) {
res = `ADD_MONTHS(${res}, ${totalMonths})`;
}

// Handle day/hour/minute/second using NUMTODSINTERVAL
if (intervalParsed.day) {
res = `${res} + NUMTODSINTERVAL(${intervalParsed.day}, 'DAY')`;
}
if (intervalParsed.hour) {
res = `${res} + NUMTODSINTERVAL(${intervalParsed.hour}, 'HOUR')`;
}
if (intervalParsed.minute) {
res = `${res} + NUMTODSINTERVAL(${intervalParsed.minute}, 'MINUTE')`;
}
if (intervalParsed.second) {
res = `${res} + NUMTODSINTERVAL(${intervalParsed.second}, 'SECOND')`;
}

return res;
}

/**
* Oracle subtraction uses ADD_MONTHS with negative values
* and subtracts NUMTODSINTERVAL for time units
*/
public subtractInterval(date: string, interval: string): string {
const intervalParsed = parseSqlInterval(interval);
let res = date;

// Handle year/month/quarter using ADD_MONTHS with negative values
let totalMonths = 0;
if (intervalParsed.year) {
totalMonths += intervalParsed.year * 12;
}
if (intervalParsed.quarter) {
totalMonths += intervalParsed.quarter * 3;
}
if (intervalParsed.month) {
totalMonths += intervalParsed.month;
}

if (totalMonths !== 0) {
res = `ADD_MONTHS(${res}, -${totalMonths})`;
}

// Handle day/hour/minute/second using NUMTODSINTERVAL with subtraction
if (intervalParsed.day) {
res = `${res} - NUMTODSINTERVAL(${intervalParsed.day}, 'DAY')`;
}
if (intervalParsed.hour) {
res = `${res} - NUMTODSINTERVAL(${intervalParsed.hour}, 'HOUR')`;
}
if (intervalParsed.minute) {
res = `${res} - NUMTODSINTERVAL(${intervalParsed.minute}, 'MINUTE')`;
}
if (intervalParsed.second) {
res = `${res} - NUMTODSINTERVAL(${intervalParsed.second}, 'SECOND')`;
}

return res;
}

public newFilter(filter) {
return new OracleFilter(this, filter);
}
Expand Down
Loading
Loading