@@ -19,7 +19,6 @@ import { assertNever } from './helpers-pure';
1919import {
2020 FromResultsViewMsg ,
2121 Interpretation ,
22- INTERPRETED_RESULTS_PER_RUN_LIMIT ,
2322 IntoResultsViewMsg ,
2423 QueryMetadata ,
2524 ResultsPaths ,
@@ -28,6 +27,8 @@ import {
2827 InterpretedResultsSortState ,
2928 SortDirection ,
3029 RAW_RESULTS_PAGE_SIZE ,
30+ INTERPRETED_RESULTS_PAGE_SIZE ,
31+ ALERTS_TABLE_NAME ,
3132} from './interface-types' ;
3233import { Logger } from './logging' ;
3334import * as messages from './messages' ;
@@ -51,6 +52,7 @@ import {
5152 jumpToLocation ,
5253} from './interface-utils' ;
5354import { getDefaultResultSetName } from './interface-types' ;
55+ import { ResultSetSchema } from './bqrs-cli-types' ;
5456
5557/**
5658 * interface.ts
@@ -95,6 +97,10 @@ function numPagesOfResultSet(resultSet: RawResultSet): number {
9597 return Math . ceil ( resultSet . schema . tupleCount / RAW_RESULTS_PAGE_SIZE ) ;
9698}
9799
100+ function numInterpretedPages ( interpretation : Interpretation | undefined ) : number {
101+ return Math . ceil ( ( interpretation ?. sarif . runs [ 0 ] . results ?. length || 0 ) / INTERPRETED_RESULTS_PAGE_SIZE ) ;
102+ }
103+
98104export class InterfaceManager extends DisposableObject {
99105 private _displayedQuery ?: CompletedQuery ;
100106 private _interpretation ?: Interpretation ;
@@ -244,7 +250,12 @@ export class InterfaceManager extends DisposableObject {
244250 ) ;
245251 break ;
246252 case 'changePage' :
247- await this . showPageOfResults ( msg . selectedTable , msg . pageNumber ) ;
253+ if ( msg . selectedTable === ALERTS_TABLE_NAME ) {
254+ await this . showPageOfInterpretedResults ( msg . pageNumber ) ;
255+ }
256+ else {
257+ await this . showPageOfRawResults ( msg . selectedTable , msg . pageNumber ) ;
258+ }
248259 break ;
249260 default :
250261 assertNever ( msg ) ;
@@ -283,7 +294,8 @@ export class InterfaceManager extends DisposableObject {
283294 return ;
284295 }
285296
286- const interpretation = await this . interpretResultsInfo (
297+ this . _interpretation = undefined ;
298+ const interpretationPage = await this . interpretResultsInfo (
287299 results . query ,
288300 results . interpretedResultsSortState
289301 ) ;
@@ -295,7 +307,6 @@ export class InterfaceManager extends DisposableObject {
295307 ) ;
296308
297309 this . _displayedQuery = results ;
298- this . _interpretation = interpretation ;
299310
300311 const panel = this . getPanel ( ) ;
301312 await this . waitForPanelLoaded ( ) ;
@@ -325,19 +336,13 @@ export class InterfaceManager extends DisposableObject {
325336
326337 const getParsedResultSets = async ( ) : Promise < ParsedResultSets > => {
327338 if ( EXPERIMENTAL_BQRS_SETTING . getValue ( ) ) {
328- const schemas = await this . cliServer . bqrsInfo (
329- results . query . resultsPaths . resultsPath ,
330- RAW_RESULTS_PAGE_SIZE
331- ) ;
332-
333- const resultSetNames = schemas [ 'result-sets' ] . map (
334- ( resultSet ) => resultSet . name
335- ) ;
339+ const resultSetSchemas = await this . getResultSetSchemas ( results ) ;
340+ const resultSetNames = resultSetSchemas . map ( schema => schema . name ) ;
336341
337342 // This may not wind up being the page we actually show, if there are interpreted results,
338343 // but speculatively send it anyway.
339344 const selectedTable = getDefaultResultSetName ( resultSetNames ) ;
340- const schema = schemas [ 'result-sets' ] . find (
345+ const schema = resultSetSchemas . find (
341346 ( resultSet ) => resultSet . name == selectedTable
342347 ) ! ;
343348 if ( schema === undefined ) {
@@ -352,12 +357,12 @@ export class InterfaceManager extends DisposableObject {
352357 ) ;
353358 const adaptedSchema = adaptSchema ( schema ) ;
354359 const resultSet = adaptBqrs ( adaptedSchema , chunk ) ;
355-
356360 return {
357361 t : 'ExtensionParsed' ,
358362 pageNumber : 0 ,
359363 numPages : numPagesOfResultSet ( resultSet ) ,
360- resultSet,
364+ numInterpretedPages : numInterpretedPages ( this . _interpretation ) ,
365+ resultSet : { t : 'RawResultSet' , ...resultSet } ,
361366 selectedTable : undefined ,
362367 resultSetNames,
363368 } ;
@@ -368,7 +373,7 @@ export class InterfaceManager extends DisposableObject {
368373
369374 await this . postMessage ( {
370375 t : 'setState' ,
371- interpretation,
376+ interpretation : interpretationPage ,
372377 origResultsPaths : results . query . resultsPaths ,
373378 resultsPath : this . convertPathToWebviewUri (
374379 results . query . resultsPaths . resultsPath
@@ -381,10 +386,48 @@ export class InterfaceManager extends DisposableObject {
381386 } ) ;
382387 }
383388
389+ /**
390+ * Show a page of interpreted results
391+ */
392+ public async showPageOfInterpretedResults (
393+ pageNumber : number
394+ ) : Promise < void > {
395+ if ( this . _displayedQuery === undefined ) {
396+ throw new Error ( 'Trying to show interpreted results but displayed query was undefined' ) ;
397+ }
398+ if ( this . _interpretation === undefined ) {
399+ throw new Error ( 'Trying to show interpreted results but interpretation was undefined' ) ;
400+ }
401+ if ( this . _interpretation . sarif . runs [ 0 ] . results === undefined ) {
402+ throw new Error ( 'Trying to show interpreted results but results were undefined' ) ;
403+ }
404+
405+ const resultSetSchemas = await this . getResultSetSchemas ( this . _displayedQuery ) ;
406+ const resultSetNames = resultSetSchemas . map ( schema => schema . name ) ;
407+
408+ await this . postMessage ( {
409+ t : 'showInterpretedPage' ,
410+ interpretation : this . getPageOfInterpretedResults ( pageNumber ) ,
411+ database : this . _displayedQuery . database ,
412+ metadata : this . _displayedQuery . query . metadata ,
413+ pageNumber,
414+ resultSetNames,
415+ numPages : numInterpretedPages ( this . _interpretation ) ,
416+ } ) ;
417+ }
418+
419+ private async getResultSetSchemas ( results : CompletedQuery ) : Promise < ResultSetSchema [ ] > {
420+ const schemas = await this . cliServer . bqrsInfo (
421+ results . query . resultsPaths . resultsPath ,
422+ RAW_RESULTS_PAGE_SIZE
423+ ) ;
424+ return schemas [ 'result-sets' ] ;
425+ }
426+
384427 /**
385428 * Show a page of raw results from the chosen table.
386429 */
387- public async showPageOfResults (
430+ public async showPageOfRawResults (
388431 selectedTable : string ,
389432 pageNumber : number
390433 ) : Promise < void > {
@@ -399,16 +442,10 @@ export class InterfaceManager extends DisposableObject {
399442 ( sortedResultsMap [ k ] = this . convertPathPropertiesToWebviewUris ( v ) )
400443 ) ;
401444
402- const schemas = await this . cliServer . bqrsInfo (
403- results . query . resultsPaths . resultsPath ,
404- RAW_RESULTS_PAGE_SIZE
405- ) ;
406-
407- const resultSetNames = schemas [ 'result-sets' ] . map (
408- ( resultSet ) => resultSet . name
409- ) ;
445+ const resultSetSchemas = await this . getResultSetSchemas ( results ) ;
446+ const resultSetNames = resultSetSchemas . map ( schema => schema . name ) ;
410447
411- const schema = schemas [ 'result-sets' ] . find (
448+ const schema = resultSetSchemas . find (
412449 ( resultSet ) => resultSet . name == selectedTable
413450 ) ! ;
414451 if ( schema === undefined )
@@ -426,8 +463,9 @@ export class InterfaceManager extends DisposableObject {
426463 const parsedResultSets : ParsedResultSets = {
427464 t : 'ExtensionParsed' ,
428465 pageNumber,
429- resultSet,
466+ resultSet : { t : 'RawResultSet' , ... resultSet } ,
430467 numPages : numPagesOfResultSet ( resultSet ) ,
468+ numInterpretedPages : numInterpretedPages ( this . _interpretation ) ,
431469 selectedTable : selectedTable ,
432470 resultSetNames,
433471 } ;
@@ -447,7 +485,7 @@ export class InterfaceManager extends DisposableObject {
447485 } ) ;
448486 }
449487
450- private async getTruncatedResults (
488+ private async _getInterpretedResults (
451489 metadata : QueryMetadata | undefined ,
452490 resultsPaths : ResultsPaths ,
453491 sourceInfo : cli . SourceInfo | undefined ,
@@ -460,37 +498,58 @@ export class InterfaceManager extends DisposableObject {
460498 resultsPaths ,
461499 sourceInfo
462500 ) ;
463- // For performance reasons, limit the number of results we try
464- // to serialize and send to the webview. TODO: possibly also
465- // limit number of paths per result, number of steps per path,
466- // or throw an error if we are in aggregate trying to send
467- // massively too much data, as it can make the extension
468- // unresponsive.
469-
470- let numTruncatedResults = 0 ;
471- sarif . runs . forEach ( ( run ) => {
472- if ( run . results !== undefined ) {
501+ sarif . runs . forEach ( run => {
502+ if ( run . results !== undefined )
473503 sortInterpretedResults ( run . results , sortState ) ;
474- if ( run . results . length > INTERPRETED_RESULTS_PER_RUN_LIMIT ) {
475- numTruncatedResults +=
476- run . results . length - INTERPRETED_RESULTS_PER_RUN_LIMIT ;
477- run . results = run . results . slice ( 0 , INTERPRETED_RESULTS_PER_RUN_LIMIT ) ;
478- }
479- }
480504 } ) ;
481- return {
505+
506+ const numTotalResults = ( ( ) => {
507+ if ( sarif . runs . length === 0 ) return 0 ;
508+ if ( sarif . runs [ 0 ] . results === undefined ) return 0 ;
509+ return sarif . runs [ 0 ] . results . length ;
510+ } ) ( ) ;
511+
512+ const interpretation : Interpretation = {
482513 sarif,
483514 sourceLocationPrefix,
484- numTruncatedResults,
515+ numTruncatedResults : 0 ,
516+ numTotalResults,
485517 sortState,
486518 } ;
519+ this . _interpretation = interpretation ;
520+ return interpretation ;
521+ }
522+
523+ private getPageOfInterpretedResults (
524+ pageNumber : number
525+ ) : Interpretation {
526+
527+ function getPageOfRun ( run : Sarif . Run ) : Sarif . Run {
528+ return {
529+ ...run , results : run . results ?. slice (
530+ INTERPRETED_RESULTS_PAGE_SIZE * pageNumber ,
531+ INTERPRETED_RESULTS_PAGE_SIZE * ( pageNumber + 1 )
532+ )
533+ } ;
534+ }
535+
536+ if ( this . _interpretation === undefined ) {
537+ throw new Error ( 'Tried to get interpreted results before interpretation finished' ) ;
538+ }
539+ if ( this . _interpretation . sarif . runs . length !== 1 ) {
540+ this . logger . log ( `Warning: SARIF file had ${ this . _interpretation . sarif . runs . length } runs, expected 1` ) ;
541+ }
542+ const interp = this . _interpretation ;
543+ return {
544+ ...interp ,
545+ sarif : { ...interp . sarif , runs : [ getPageOfRun ( interp . sarif . runs [ 0 ] ) ] } ,
546+ } ;
487547 }
488548
489549 private async interpretResultsInfo (
490550 query : QueryInfo ,
491551 sortState : InterpretedResultsSortState | undefined
492552 ) : Promise < Interpretation | undefined > {
493- let interpretation : Interpretation | undefined = undefined ;
494553 if (
495554 ( await query . canHaveInterpretedResults ( ) ) &&
496555 query . quickEvalPosition === undefined // never do results interpretation if quickEval
@@ -507,7 +566,7 @@ export class InterfaceManager extends DisposableObject {
507566 sourceArchive : sourceArchiveUri . fsPath ,
508567 sourceLocationPrefix,
509568 } ;
510- interpretation = await this . getTruncatedResults (
569+ await this . _getInterpretedResults (
511570 query . metadata ,
512571 query . resultsPaths ,
513572 sourceInfo ,
@@ -522,7 +581,7 @@ export class InterfaceManager extends DisposableObject {
522581 ) ;
523582 }
524583 }
525- return interpretation ;
584+ return this . _interpretation && this . getPageOfInterpretedResults ( 0 ) ;
526585 }
527586
528587 private async showResultsAsDiagnostics (
@@ -541,7 +600,8 @@ export class InterfaceManager extends DisposableObject {
541600 sourceArchive : sourceArchiveUri . fsPath ,
542601 sourceLocationPrefix,
543602 } ;
544- const interpretation = await this . getTruncatedResults (
603+ // TODO: Performance-testing to determine whether this truncation is necessary.
604+ const interpretation = await this . _getInterpretedResults (
545605 metadata ,
546606 resultsInfo ,
547607 sourceInfo ,
0 commit comments