@@ -22,8 +22,8 @@ import {
2222 DriverInterface ,
2323 InlineTable ,
2424 SaveCancelFn ,
25- StreamOptions ,
26- UnloadOptions
25+ StreamOptions , TableStructure ,
26+ UnloadOptions ,
2727} from '@cubejs-backend/base-driver' ;
2828import { CubeStoreDriver } from '@cubejs-backend/cubestore-driver' ;
2929import { PreAggTableToTempTable , Query , QueryBody , QueryCache , QueryTuple , QueryWithParams } from './QueryCache' ;
@@ -263,6 +263,8 @@ class PreAggregationLoadCache {
263263
264264 private tables : { [ redisKey : string ] : TableCacheEntry [ ] } ;
265265
266+ private tableColumnTypes : { [ cacheKey : string ] : { [ tableName : string ] : TableStructure } } ;
267+
266268 // TODO this is in memory cache structure as well however it depends on
267269 // data source only and load cache is per data source for now.
268270 // Make it per data source key in case load cache scope is broaden.
@@ -290,10 +292,11 @@ class PreAggregationLoadCache {
290292 this . tablePrefixes = options . tablePrefixes ;
291293 this . versionEntries = { } ;
292294 this . tables = { } ;
295+ this . tableColumnTypes = { } ;
293296 }
294297
295298 protected async tablesFromCache ( preAggregation , forceRenew ?) {
296- let tables = forceRenew ? null : await this . queryCache . getCacheDriver ( ) . get ( this . tablesRedisKey ( preAggregation ) ) ;
299+ let tables = forceRenew ? null : await this . queryCache . getCacheDriver ( ) . get ( this . tablesCachePrefixKey ( preAggregation ) ) ;
297300 if ( ! tables ) {
298301 tables = await this . preAggregations . getLoadCacheQueue ( this . dataSource ) . executeInQueue (
299302 'query' ,
@@ -315,7 +318,7 @@ class PreAggregationLoadCache {
315318
316319 const newTables = await this . fetchTablesNoCache ( preAggregation ) ;
317320 await this . queryCache . getCacheDriver ( ) . set (
318- this . tablesRedisKey ( preAggregation ) ,
321+ this . tablesCachePrefixKey ( preAggregation ) ,
319322 newTables ,
320323 this . preAggregations . options . preAggregationsSchemaCacheExpire || 60 * 60
321324 ) ;
@@ -332,12 +335,12 @@ class PreAggregationLoadCache {
332335 return client . getTablesQuery ( preAggregation . preAggregationsSchema ) ;
333336 }
334337
335- public tablesRedisKey ( preAggregation : PreAggregationDescription ) {
338+ public tablesCachePrefixKey ( preAggregation : PreAggregationDescription ) {
336339 return this . queryCache . getKey ( 'SQL_PRE_AGGREGATIONS_TABLES' , `${ preAggregation . dataSource } ${ preAggregation . preAggregationsSchema } ${ preAggregation . external ? '_EXT' : '' } ` ) ;
337340 }
338341
339342 protected async getTablesQuery ( preAggregation ) {
340- const redisKey = this . tablesRedisKey ( preAggregation ) ;
343+ const redisKey = this . tablesCachePrefixKey ( preAggregation ) ;
341344 if ( ! this . tables [ redisKey ] ) {
342345 const tables = this . preAggregations . options . skipExternalCacheAndQueue && preAggregation . external ?
343346 await this . fetchTablesNoCache ( preAggregation ) :
@@ -350,6 +353,22 @@ class PreAggregationLoadCache {
350353 return this . tables [ redisKey ] ;
351354 }
352355
356+ protected async getTableColumnTypes ( preAggregation : PreAggregationDescription , tableName : string ) : Promise < TableStructure > {
357+ const prefixKey = this . tablesCachePrefixKey ( preAggregation ) ;
358+ if ( ! this . tableColumnTypes [ prefixKey ] ?. [ tableName ] ) {
359+ if ( ! this . preAggregations . options . skipExternalCacheAndQueue && preAggregation . external ) {
360+ throw new Error ( `Lambda union with source data feature is supported only by external rollups stored in Cube Store but was invoked for '${ preAggregation . preAggregationId } '` ) ;
361+ }
362+ const client = await this . externalDriverFactory ( ) ;
363+ const columnTypes = await client . tableColumnTypes ( tableName ) ;
364+ if ( ! this . tableColumnTypes [ prefixKey ] ) {
365+ this . tableColumnTypes [ prefixKey ] = { } ;
366+ }
367+ this . tableColumnTypes [ prefixKey ] [ tableName ] = columnTypes ;
368+ }
369+ return this . tableColumnTypes [ prefixKey ] [ tableName ] ;
370+ }
371+
353372 private async calculateVersionEntries ( preAggregation ) : Promise < VersionEntriesObj > {
354373 let versionEntries = tablesToVersionEntries (
355374 preAggregation . preAggregationsSchema ,
@@ -394,7 +413,7 @@ class PreAggregationLoadCache {
394413 if ( this . tablePrefixes && ! this . tablePrefixes . find ( p => preAggregation . tableName . split ( '.' ) [ 1 ] . startsWith ( p ) ) ) {
395414 throw new Error ( `Load cache tries to load table ${ preAggregation . tableName } outside of tablePrefixes filter: ${ this . tablePrefixes . join ( ', ' ) } ` ) ;
396415 }
397- const redisKey = this . tablesRedisKey ( preAggregation ) ;
416+ const redisKey = this . tablesCachePrefixKey ( preAggregation ) ;
398417 if ( ! this . versionEntries [ redisKey ] ) {
399418 this . versionEntries [ redisKey ] = this . calculateVersionEntries ( preAggregation ) . catch ( e => {
400419 delete this . versionEntries [ redisKey ] ;
@@ -450,6 +469,7 @@ class PreAggregationLoadCache {
450469 protected async reset ( preAggregation ) {
451470 await this . tablesFromCache ( preAggregation , true ) ;
452471 this . tables = { } ;
472+ this . tableColumnTypes = { } ;
453473 this . queryStageState = undefined ;
454474 this . versionEntries = { } ;
455475 }
@@ -1655,8 +1675,9 @@ export class PreAggregationPartitionRangeLoader {
16551675
16561676 if ( this . preAggregation . rollupLambdaId ) {
16571677 if ( this . lambdaQuery && loadResults . length > 0 ) {
1658- const { buildRangeEnd } = loadResults [ loadResults . length - 1 ] ;
1659- lambdaTable = await this . downloadLambdaTable ( buildRangeEnd ) ;
1678+ const { buildRangeEnd, targetTableName } = loadResults [ loadResults . length - 1 ] ;
1679+ const lambdaTypes = await this . loadCache . getTableColumnTypes ( this . preAggregation , targetTableName ) ;
1680+ lambdaTable = await this . downloadLambdaTable ( buildRangeEnd , lambdaTypes ) ;
16601681 }
16611682 const rollupLambdaResults = this . preAggregationsTablesToTempTables . filter ( tempTableResult => tempTableResult [ 1 ] . rollupLambdaId === this . preAggregation . rollupLambdaId ) ;
16621683 const filteredResults = loadResults . filter (
@@ -1708,7 +1729,7 @@ export class PreAggregationPartitionRangeLoader {
17081729 /**
17091730 * Downloads the lambda table from the source DB.
17101731 */
1711- private async downloadLambdaTable ( fromDate : string ) : Promise < InlineTable > {
1732+ private async downloadLambdaTable ( fromDate : string , lambdaTypes : TableStructure ) : Promise < InlineTable > {
17121733 const { sqlAndParams, cacheKeyQueries } = this . lambdaQuery ;
17131734 const [ query , params ] = sqlAndParams ;
17141735 const values = params . map ( ( p ) => {
@@ -1733,6 +1754,7 @@ export class PreAggregationPartitionRangeLoader {
17331754 dataSource : this . dataSource ,
17341755 external : false ,
17351756 useCsvQuery : true ,
1757+ lambdaTypes,
17361758 }
17371759 ) ;
17381760 if ( data . rowCount === this . options . maxSourceRowLimit ) {
@@ -2393,7 +2415,7 @@ export class PreAggregations {
23932415 preAggregations . map (
23942416 async preAggregation => {
23952417 const { dataSource, preAggregationsSchema } = preAggregation ;
2396- const cacheKey = getLoadCacheByDataSource ( dataSource , preAggregationsSchema ) . tablesRedisKey ( preAggregation ) ;
2418+ const cacheKey = getLoadCacheByDataSource ( dataSource , preAggregationsSchema ) . tablesCachePrefixKey ( preAggregation ) ;
23972419 if ( ! firstByCacheKey [ cacheKey ] ) {
23982420 firstByCacheKey [ cacheKey ] = getLoadCacheByDataSource ( dataSource , preAggregationsSchema ) . getVersionEntries ( preAggregation ) ;
23992421 const res = await firstByCacheKey [ cacheKey ] ;
0 commit comments