query error markers

This commit is contained in:
Jan Prochazka 2022-09-25 19:45:47 +02:00
parent 2f820d8dac
commit 1a7f06342f
9 changed files with 102 additions and 36 deletions

View File

@ -101,8 +101,9 @@ class TableWriter {
} }
class StreamHandler { class StreamHandler {
constructor(resultIndexHolder, resolve) { constructor(resultIndexHolder, resolve, startLine) {
this.recordset = this.recordset.bind(this); this.recordset = this.recordset.bind(this);
this.startLine = startLine;
this.row = this.row.bind(this); this.row = this.row.bind(this);
// this.error = this.error.bind(this); // this.error = this.error.bind(this);
this.done = this.done.bind(this); this.done = this.done.bind(this);
@ -155,14 +156,20 @@ class StreamHandler {
this.resolve(); this.resolve();
} }
info(info) { info(info) {
if (info.line != null) {
info = {
...info,
line: this.startLine + info.line,
};
}
process.send({ msgtype: 'info', info }); process.send({ msgtype: 'info', info });
} }
} }
function handleStream(driver, resultIndexHolder, sql) { function handleStream(driver, resultIndexHolder, sqlItem) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const handler = new StreamHandler(resultIndexHolder, resolve); const handler = new StreamHandler(resultIndexHolder, resolve, sqlItem.trimStart.line);
driver.stream(systemConnection, sql, handler); driver.stream(systemConnection, sqlItem.text, handler);
}); });
} }
@ -221,7 +228,10 @@ async function handleExecuteQuery({ sql }) {
const resultIndexHolder = { const resultIndexHolder = {
value: 0, value: 0,
}; };
for (const sqlItem of splitQuery(sql, driver.getQuerySplitterOptions('stream'))) { for (const sqlItem of splitQuery(sql, {
...driver.getQuerySplitterOptions('stream'),
returnRichInfo: true,
})) {
await handleStream(driver, resultIndexHolder, sqlItem); await handleStream(driver, resultIndexHolder, sqlItem);
// const handler = new StreamHandler(resultIndex); // const handler = new StreamHandler(resultIndex);
// const stream = await driver.stream(systemConnection, sqlItem, handler); // const stream = await driver.stream(systemConnection, sqlItem, handler);

View File

@ -65,7 +65,7 @@
let changeIndex = 0; let changeIndex = 0;
let rowCountLoaded = null; let rowCountLoaded = null;
const throttleLoadNext = _.throttle(() => domGrid.resetLoadedAll(), 500); const throttleLoadNext = _.throttle(() => domGrid?.resetLoadedAll(), 500);
const handleJslDataStats = stats => { const handleJslDataStats = stats => {
if (stats.changeIndex < changeIndex) return; if (stats.changeIndex < changeIndex) return;

View File

@ -156,6 +156,7 @@
export let splitterOptions = null; export let splitterOptions = null;
export let onKeyDown = null; export let onKeyDown = null;
export let onExecuteFragment = null; export let onExecuteFragment = null;
export let errorMessages = null;
const tabVisible: any = getContext('tabVisible'); const tabVisible: any = getContext('tabVisible');
@ -184,16 +185,28 @@
return editor; return editor;
} }
export function getCurrentCommandText(): string { export function getCurrentCommandText(): { text: string; line?: number } {
if (currentPart != null) return currentPart.text; if (currentPart != null) {
if (!editor) return ''; return {
text: currentPart.text,
line: currentPart.trimStart.line,
};
}
if (!editor) return { text: '' };
const selectedText = editor.getSelectedText(); const selectedText = editor.getSelectedText();
if (selectedText) return selectedText; if (selectedText)
return {
text: selectedText,
line: editor.getSelectionRange().start.row,
};
if (editor.getHighlightActiveLine()) { if (editor.getHighlightActiveLine()) {
const line = editor.getSelectionRange().start.row; const line = editor.getSelectionRange().start.row;
return editor.session.getLine(line); return {
text: editor.session.getLine(line),
line,
};
} }
return ''; return { text: '' };
} }
export function getCodeCompletionCommandText() { export function getCodeCompletionCommandText() {
@ -292,13 +305,25 @@
} }
function updateAnnotations() { function updateAnnotations() {
editor.session.setAnnotations( editor?.session?.setAnnotations([
(queryParts || []).map(part => ({ ...(queryParts || [])
row: part.trimStart.line, .filter(part => !(errorMessages || []).find(err => err.line == part.trimStart.line))
text: part.text, .map(part => ({
className: 'ace-gutter-sql-run', row: part.trimStart.line,
})) text: part.text,
); className: 'ace-gutter-sql-run',
})),
...(errorMessages || []).map(error => ({
row: error.line,
text: error.message,
type: 'error',
})),
]);
}
$: {
errorMessages;
updateAnnotations();
} }
const handleContextMenu = e => { const handleContextMenu = e => {
@ -455,10 +480,10 @@
const part = (queryParts || []).find(part => part.trimStart.line == row); const part = (queryParts || []).find(part => part.trimStart.line == row);
if (part && onExecuteFragment) { if (part && onExecuteFragment) {
onExecuteFragment(part.text); onExecuteFragment(part.text, part.trimStart.line);
e.stop(); e.stop();
editor.moveCursorTo(part.trimStart.line, 0); editor.moveCursorTo(part.trimStart.line, 0);
editor.selection.clearSelection() editor.selection.clearSelection();
} }
}, },
true true

View File

@ -18,6 +18,7 @@
export let items: any[]; export let items: any[];
export let showProcedure = false; export let showProcedure = false;
export let showLine = false; export let showLine = false;
export let startLine = 0;
$: time0 = items[0] && new Date(items[0].time).getTime(); $: time0 = items[0] && new Date(items[0].time).getTime();
@ -58,7 +59,7 @@
<td>{row.procedure || ''}</td> <td>{row.procedure || ''}</td>
{/if} {/if}
{#if showLine} {#if showLine}
<td>{row.line || ''}</td> <td>{row.line == null ? '' : row.line + 1 + startLine}</td>
{/if} {/if}
</tr> </tr>
{/each} {/each}

View File

@ -13,8 +13,11 @@
export let eventName; export let eventName;
export let executeNumber; export let executeNumber;
export let showNoMessagesAlert = false; export let showNoMessagesAlert = false;
export let startLine = 0;
export let onChangeErrors = null;
const cachedMessagesRef = createRef([]); const cachedMessagesRef = createRef([]);
const lastErrorMessageCountRef = createRef(0);
let displayedMessages = []; let displayedMessages = [];
@ -44,11 +47,26 @@
} }
} }
$: {
if (onChangeErrors) {
const errors = displayedMessages.filter(x => x.severity == 'error');
if (lastErrorMessageCountRef.get() != errors.length) {
onChangeErrors(
errors.map(err => ({
...err,
line: err.line == null ? null : err.line + startLine,
}))
);
lastErrorMessageCountRef.set(errors.length);
}
}
}
$: $effect; $: $effect;
</script> </script>
{#if showNoMessagesAlert && (!displayedMessages || displayedMessages.length == 0)} {#if showNoMessagesAlert && (!displayedMessages || displayedMessages.length == 0)}
<ErrorInfo message="No messages" icon="img alert" /> <ErrorInfo message="No messages" icon="img alert" />
{:else} {:else}
<MessageView items={displayedMessages} on:messageclick {showProcedure} {showLine} /> <MessageView items={displayedMessages} on:messageclick {showProcedure} {showLine} {startLine} />
{/if} {/if}

View File

@ -32,7 +32,7 @@
return domEditor.getEditor(); return domEditor.getEditor();
} }
export function getCurrentCommandText(): string { export function getCurrentCommandText(): { text: string; line?: number } {
return domEditor.getCurrentCommandText(); return domEditor.getCurrentCommandText();
} }

View File

@ -86,10 +86,11 @@
let busy = false; let busy = false;
let executeNumber = 0; let executeNumber = 0;
let executeStartLine = 0;
let visibleResultTabs = false; let visibleResultTabs = false;
let sessionId = null; let sessionId = null;
let resultCount; let resultCount;
let errorMessages;
let domEditor; let domEditor;
$: connection = useConnectionInfo({ conid }); $: connection = useConnectionInfo({ conid });
@ -143,13 +144,14 @@
return !!conid && (!$connection?.isReadOnly || driver?.readOnlySessions); return !!conid && (!$connection?.isReadOnly || driver?.readOnlySessions);
} }
async function executeCore(sql) { async function executeCore(sql, startLine = 0) {
if (busy) return; if (busy) return;
if (!sql || !sql.trim()) { if (!sql || !sql.trim()) {
showSnackbarError('Skipped executing empty query'); showSnackbarError('Skipped executing empty query');
return; return;
} }
executeStartLine = startLine;
executeNumber++; executeNumber++;
visibleResultTabs = true; visibleResultTabs = true;
@ -179,13 +181,14 @@
} }
export async function executeCurrent() { export async function executeCurrent() {
const sql = domEditor.getCurrentCommandText(); const cmd = domEditor.getCurrentCommandText();
await executeCore(sql); await executeCore(cmd.text, cmd.line);
} }
export async function execute() { export async function execute() {
const selectedText = domEditor.getEditor().getSelectedText(); const selectedText = domEditor.getEditor().getSelectedText();
await executeCore(selectedText || $editorValue); const startLine = domEditor.getEditor().getSelectionRange().start.row;
await executeCore(selectedText || $editorValue, selectedText ? startLine : 0);
} }
export async function kill() { export async function kill() {
@ -257,6 +260,10 @@
: null, : null,
}); });
function handleChangeErrors(errors) {
errorMessages = errors;
}
function createMenu() { function createMenu() {
return [ return [
{ command: 'query.execute' }, { command: 'query.execute' },
@ -289,13 +296,17 @@
splitterOptions={driver?.getQuerySplitterOptions('script')} splitterOptions={driver?.getQuerySplitterOptions('script')}
value={$editorState.value || ''} value={$editorState.value || ''}
menu={createMenu()} menu={createMenu()}
on:input={e => setEditorData(e.detail)} on:input={e => {
setEditorData(e.detail);
errorMessages = [];
}}
on:focus={() => { on:focus={() => {
activator.activate(); activator.activate();
invalidateCommands(); invalidateCommands();
}} }}
bind:this={domEditor} bind:this={domEditor}
onExecuteFragment={sql => executeCore(sql)} onExecuteFragment={(sql, startLine) => executeCore(sql, startLine)}
{errorMessages}
/> />
{:else} {:else}
<AceEditor <AceEditor
@ -319,8 +330,10 @@
eventName={sessionId ? `session-info-${sessionId}` : null} eventName={sessionId ? `session-info-${sessionId}` : null}
on:messageClick={handleMesageClick} on:messageClick={handleMesageClick}
{executeNumber} {executeNumber}
startLine={executeStartLine}
showProcedure showProcedure
showLine showLine
onChangeErrors={handleChangeErrors}
/> />
</svelte:fragment> </svelte:fragment>
</ResultTabs> </ResultTabs>

View File

@ -134,7 +134,7 @@ async function tediousStream(pool, sql, options) {
const { message, lineNumber, procName } = info; const { message, lineNumber, procName } = info;
options.info({ options.info({
message, message,
line: lineNumber, line: lineNumber != null && lineNumber > 0 ? lineNumber - 1 : lineNumber,
procedure: procName, procedure: procName,
time: new Date(), time: new Date(),
severity: 'info', severity: 'info',
@ -144,7 +144,7 @@ async function tediousStream(pool, sql, options) {
const { message, lineNumber, procName } = error; const { message, lineNumber, procName } = error;
options.info({ options.info({
message, message,
line: lineNumber, line: lineNumber != null && lineNumber > 0 ? lineNumber - 1 : lineNumber,
procedure: procName, procedure: procName,
time: new Date(), time: new Date(),
severity: 'error', severity: 'error',

View File

@ -112,11 +112,10 @@ const drivers = driverBases.map(driverBase => ({
const handleError = error => { const handleError = error => {
console.log('ERROR', error); console.log('ERROR', error);
const { message, lineNumber, procName } = error; const { message } = error;
options.info({ options.info({
message, message,
line: lineNumber, line: 0,
procedure: procName,
time: new Date(), time: new Date(),
severity: 'error', severity: 'error',
}); });