1// Copyright (C) 2018 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import {Engine} from './engine'; 16import {Row} from './query_result'; 17 18const MAX_DISPLAY_ROWS = 10000; 19 20export interface QueryResponse { 21 id: string; 22 query: string; 23 error?: string; 24 totalRowCount: number; 25 durationMs: number; 26 columns: string[]; 27 rows: Row[]; 28 statementCount: number; 29 statementWithOutputCount: number; 30} 31 32export async function runQuery( 33 queryId: string, sqlQuery: string, engine: Engine): Promise<QueryResponse> { 34 const startMs = performance.now(); 35 const queryRes = engine.query(sqlQuery); 36 37 // TODO(primiano): once the controller thread is gone we should pass down 38 // the result objects directly to the frontend, iterate over the result 39 // and deal with pagination there. For now we keep the old behavior and 40 // truncate to 10k rows. 41 42 try { 43 await queryRes.waitAllRows(); 44 } catch { 45 // In the case of a query error we don't want the exception to bubble up 46 // as a crash. The |queryRes| object will be populated anyways. 47 // queryRes.error() is used to tell if the query errored or not. If it 48 // errored, the frontend will show a graceful message instead. 49 } 50 51 const durationMs = performance.now() - startMs; 52 const rows: Row[] = []; 53 const columns = queryRes.columns(); 54 let numRows = 0; 55 for (const iter = queryRes.iter({}); iter.valid(); iter.next()) { 56 const row: Row = {}; 57 for (const colName of columns) { 58 const value = iter.get(colName); 59 row[colName] = value === null ? 'NULL' : value; 60 } 61 rows.push(row); 62 if (++numRows >= MAX_DISPLAY_ROWS) break; 63 } 64 65 const result: QueryResponse = { 66 id: queryId, 67 query: sqlQuery, 68 durationMs, 69 error: queryRes.error(), 70 totalRowCount: queryRes.numRows(), 71 columns, 72 rows, 73 statementCount: queryRes.statementCount(), 74 statementWithOutputCount: queryRes.statementWithOutputCount(), 75 }; 76 return result; 77}