Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@
"command": "codeQL.runQuery",
"title": "CodeQL: Run Query"
},
{
"command": "codeQL.runQueryOnMultipleDatabases",
"title": "CodeQL: Run Query on Multiple Databases"
},
{
"command": "codeQL.runRemoteQuery",
"title": "CodeQL: Run Remote Query"
Expand Down Expand Up @@ -680,6 +684,10 @@
"command": "codeQL.runQuery",
"when": "resourceLangId == ql && resourceExtname == .ql"
},
{
"command": "codeQL.runQueryOnMultipleDatabases",
"when": "resourceLangId == ql && resourceExtname == .ql"
},
{
"command": "codeQL.runRemoteQuery",
"when": "config.codeQL.canary && editorLangId == ql && resourceExtname == .ql"
Expand Down Expand Up @@ -830,6 +838,10 @@
"command": "codeQL.runQuery",
"when": "editorLangId == ql && resourceExtname == .ql"
},
{
"command": "codeQL.runQueryOnMultipleDatabases",
"when": "editorLangId == ql && resourceExtname == .ql"
},
{
"command": "codeQL.runRemoteQuery",
"when": "config.codeQL.canary && editorLangId == ql && resourceExtname == .ql"
Expand Down
68 changes: 62 additions & 6 deletions extensions/ql-vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
Uri,
window as Window,
env,
window
window,
QuickPickItem
} from 'vscode';
import { LanguageClient } from 'vscode-languageclient';
import * as os from 'os';
Expand All @@ -29,7 +30,7 @@ import {
QueryServerConfigListener
} from './config';
import * as languageSupport from './languageSupport';
import { DatabaseManager } from './databases';
import { DatabaseItem, DatabaseManager } from './databases';
import { DatabaseUI } from './databases-ui';
import {
TemplateQueryDefinitionProvider,
Expand Down Expand Up @@ -467,9 +468,11 @@ async function activateWithInstalledDistribution(
selectedQuery: Uri | undefined,
progress: ProgressCallback,
token: CancellationToken,
databaseItem: DatabaseItem | undefined,
): Promise<void> {
if (qs !== undefined) {
const dbItem = await databaseUI.getDatabaseItem(progress, token);
// If no databaseItem is specified, use the database currently selected in the Databases UI
const dbItem = databaseItem || await databaseUI.getDatabaseItem(progress, token);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: you could use only one variable throughout:

databaseItem = databaseItem || await databaseUI.getDatabaseItem(progress, token);

and replace dbItem in the two uses below with databaseItem.

Why do this? To avoid accidentally introducing code later that uses databaseItem when we should be using dbItem. (This is a classic mistake I have made often when two variables have similar names but only one variable has the fully initialised value...)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed! Thanks for the tip—I can definitely see myself getting confused by variables otherwise 🙃

if (dbItem === undefined) {
throw new Error('Can\'t run query without a selected database');
}
Expand Down Expand Up @@ -549,13 +552,66 @@ async function activateWithInstalledDistribution(
progress: ProgressCallback,
token: CancellationToken,
uri: Uri | undefined
) => await compileAndRunQuery(false, uri, progress, token),
) => await compileAndRunQuery(false, uri, progress, token, undefined),
{
title: 'Running query',
cancellable: true
}
)
);
interface DatabaseQuickPickItem extends QuickPickItem {
databaseItem: DatabaseItem;
}
ctx.subscriptions.push(
commandRunnerWithProgress(
'codeQL.runQueryOnMultipleDatabases',
async (
progress: ProgressCallback,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future note: A cool enhancement might be to have the progress bar reflect how many of the selected databases the query has completed on. Dealing with progress monitors is tricky, so let's think about this later, writing it here just to record the idea.

token: CancellationToken,
uri: Uri | undefined
) => {
const quickPickItems = dbm.databaseItems.map<DatabaseQuickPickItem>(dbItem => (
{
databaseItem: dbItem,
label: dbItem.name,
description: dbItem.language,
Comment thread
shati-patel marked this conversation as resolved.
}
));
/**
* Databases that were selected in the quick pick menu.
*/
const quickpick = await window.showQuickPick<DatabaseQuickPickItem>(
quickPickItems,
{ canPickMany: true }
);
if (quickpick !== undefined) {
// Collect all skipped databases and display them at the end (instead of popping up individual errors)
const skippedDatabases = [];
const errors = [];
for (const item of quickpick) {
try {
await compileAndRunQuery(false, uri, progress, token, item.databaseItem);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't know the language of the query at this point do we? It would be very cool to automatically filter out databases that are of the wrong language. But no problem if we can't do that yet.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't know the language of the query at this point do we? It would be very cool to automatically filter out databases that are of the wrong language. But no problem if we can't do that yet.

Indeed 😅 I couldn't work out how to extract that language information before displaying the quick pick, so I stuck with this for now!

} catch (error) {
skippedDatabases.push(item.label);
errors.push(error.message);
}
}
if (skippedDatabases.length > 0) {
void logger.log(`Errors:\n${errors.join('\n')}`);
void helpers.showAndLogWarningMessage(
`The following databases were skipped:\n${skippedDatabases.join('\n')}.\nFor details about the errors, see the logs.`
);
}
} else {
void helpers.showAndLogErrorMessage('No databases selected.');
}
},
{
title: 'Running query on selected databases',
cancellable: true
}
)
);
ctx.subscriptions.push(
commandRunnerWithProgress(
'codeQL.runQueries',
Expand Down Expand Up @@ -611,7 +667,7 @@ async function activateWithInstalledDistribution(
});

await Promise.all(queryUris.map(async uri =>
compileAndRunQuery(false, uri, wrappedProgress, token)
compileAndRunQuery(false, uri, wrappedProgress, token, undefined)
.then(() => queriesRemaining--)
));
},
Expand All @@ -627,7 +683,7 @@ async function activateWithInstalledDistribution(
progress: ProgressCallback,
token: CancellationToken,
uri: Uri | undefined
) => await compileAndRunQuery(true, uri, progress, token),
) => await compileAndRunQuery(true, uri, progress, token, undefined),
{
title: 'Running query',
cancellable: true
Expand Down
2 changes: 1 addition & 1 deletion extensions/ql-vscode/src/run-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ export async function compileAndRunQueryAgainstDatabase(
const dbSchemaName = path.basename(db.contents.dbSchemeUri.fsPath);
if (querySchemaName != dbSchemaName) {
void logger.log(`Query schema was ${querySchemaName}, but database schema was ${dbSchemaName}.`);
throw new Error(`The query ${path.basename(queryPath)} cannot be run against the selected database: their target languages are different. Please select a different database and try again.`);
throw new Error(`The query ${path.basename(queryPath)} cannot be run against the selected database (${db.name}): their target languages are different. Please select a different database and try again.`);
}

const qlProgram: messages.QlProgram = {
Expand Down