• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}