diff --git a/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts b/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts index d5e4871b88497..a7fcbeb90a26d 100644 --- a/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts +++ b/packages/cubejs-schema-compiler/src/adapter/OracleQuery.ts @@ -71,15 +71,18 @@ export class OracleQuery extends BaseQuery { } public dateTimeCast(value) { - return `to_date(:"${value}", 'YYYY-MM-DD"T"HH24:MI:SS"Z"')`; + // Use timezone-aware parsing for ISO 8601 with milliseconds and trailing 'Z', then cast to DATE + // to preserve index-friendly comparisons against DATE columns. + return `CAST(TO_TIMESTAMP_TZ(:"${value}", 'YYYY-MM-DD"T"HH24:MI:SS.FF"Z"') AS DATE)`; } public timeStampCast(value) { - return this.dateTimeCast(value); + // Return timezone-aware timestamp for TIMESTAMP comparisons + return `TO_TIMESTAMP_TZ(:"${value}", 'YYYY-MM-DD"T"HH24:MI:SS.FF"Z"')`; } public timeStampParam(timeDimension) { - return timeDimension.dateFieldType() === 'string' ? ':"?"' : this.timeStampCast('?'); + return timeDimension.dateFieldType() === 'string' ? ':"?"' : this.dateTimeCast('?'); } public timeGroupedColumn(granularity, dimension) { diff --git a/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts b/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts new file mode 100644 index 0000000000000..97e182f06ccd8 --- /dev/null +++ b/packages/cubejs-schema-compiler/test/unit/oracle-query.test.ts @@ -0,0 +1,54 @@ +import { OracleQuery } from '../../src/adapter/OracleQuery'; +import { prepareJsCompiler } from './PrepareCompiler'; + +describe('OracleQuery', () => { + const { compiler, joinGraph, cubeEvaluator } = prepareJsCompiler(` + cube(\`visitors\`, { + sql: \` + select * from visitors + \`, + + measures: { + count: { + type: 'count' + } + }, + + dimensions: { + id: { + sql: 'id', + type: 'number', + primaryKey: true + }, + createdAt: { + type: 'time', + sql: 'created_at' + } + } + }) + `, { adapter: 'oracle' }); + + it('uses TO_TIMESTAMP_TZ with milliseconds precision and preserves trailing Z', async () => { + await compiler.compile(); + + const query = new OracleQuery( + { joinGraph, cubeEvaluator, compiler }, + { + measures: ['visitors.count'], + timeDimensions: [ + { + dimension: 'visitors.createdAt', + dateRange: ['2024-02-01', '2024-02-02'], + granularity: 'day' + } + ], + timezone: 'UTC' + } + ); + + const [sql, params] = query.buildSqlAndParams(); + + expect(sql).toContain('TO_TIMESTAMP_TZ(:"?", \'YYYY-MM-DD"T"HH24:MI:SS.FF"Z"\')'); + expect(params).toEqual(['2024-02-01T00:00:00.000Z', '2024-02-02T23:59:59.999Z']); + }); +});