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 {EngineProxy} from './engine'; 16import {Row} from './query_result'; 17 18const MAX_DISPLAY_ROWS = 10000; 19 20export interface QueryResponse { 21 query: string; 22 error?: string; 23 totalRowCount: number; 24 durationMs: number; 25 columns: string[]; 26 rows: Row[]; 27 statementCount: number; 28 statementWithOutputCount: number; 29} 30 31export async function runQuery( 32 sqlQuery: string, engine: EngineProxy): Promise<QueryResponse> { 33 const startMs = performance.now(); 34 const queryRes = engine.query(sqlQuery); 35 36 // TODO(primiano): once the controller thread is gone we should pass down 37 // the result objects directly to the frontend, iterate over the result 38 // and deal with pagination there. For now we keep the old behavior and 39 // truncate to 10k rows. 40 41 try { 42 await queryRes.waitAllRows(); 43 } catch { 44 // In the case of a query error we don't want the exception to bubble up 45 // as a crash. The |queryRes| object will be populated anyways. 46 // queryRes.error() is used to tell if the query errored or not. If it 47 // errored, the frontend will show a graceful message instead. 48 } 49 50 const durationMs = performance.now() - startMs; 51 const rows: Row[] = []; 52 const columns = queryRes.columns(); 53 let numRows = 0; 54 for (const iter = queryRes.iter({}); iter.valid(); iter.next()) { 55 const row: Row = {}; 56 for (const colName of columns) { 57 const value = iter.get(colName); 58 row[colName] = value === null ? 'NULL' : value; 59 } 60 rows.push(row); 61 if (++numRows >= MAX_DISPLAY_ROWS) break; 62 } 63 64 const result: QueryResponse = { 65 query: sqlQuery, 66 durationMs, 67 error: queryRes.error(), 68 totalRowCount: queryRes.numRows(), 69 columns, 70 rows, 71 statementCount: queryRes.statementCount(), 72 statementWithOutputCount: queryRes.statementWithOutputCount(), 73 }; 74 return result; 75} 76