diff --git a/web-console/src/components/json-input/json-input.tsx b/web-console/src/components/json-input/json-input.tsx
index e3467303e36..b206db77e99 100644
--- a/web-console/src/components/json-input/json-input.tsx
+++ b/web-console/src/components/json-input/json-input.tsx
@@ -67,7 +67,7 @@ interface InternalValue {
interface JsonInputProps {
value: any;
onChange: (value: any) => void;
- onError?: (error: Error) => void;
+ setError?: (error: Error | undefined) => void;
placeholder?: string;
focus?: boolean;
width?: string;
@@ -76,7 +76,7 @@ interface JsonInputProps {
}
export const JsonInput = React.memo(function JsonInput(props: JsonInputProps) {
- const { onChange, onError, placeholder, focus, width, height, value, issueWithValue } = props;
+ const { onChange, setError, placeholder, focus, width, height, value, issueWithValue } = props;
const [internalValue, setInternalValue] = useState(() => ({
value,
stringified: stringifyJson(value),
@@ -121,9 +121,8 @@ export const JsonInput = React.memo(function JsonInput(props: JsonInputProps) {
stringified: inputJson,
});
- if (error) {
- onError?.(error);
- } else {
+ setError?.(error);
+ if (!error) {
onChange(value);
}
diff --git a/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx b/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx
index 7c70d22571a..8a3a232072e 100644
--- a/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx
+++ b/web-console/src/dialogs/compaction-config-dialog/compaction-config-dialog.tsx
@@ -87,7 +87,13 @@ export const CompactionConfigDialog = React.memo(function CompactionConfigDialog
)}
-
+ {
+ setJsonError(undefined);
+ setCurrentTab(t);
+ }}
+ />
{currentTab === 'form' ? (
{
- setCurrentConfig(v);
- setJsonError(undefined);
- }}
- onError={setJsonError}
+ onChange={setCurrentConfig}
+ setError={setJsonError}
issueWithValue={value => AutoForm.issueWithModel(value, COMPACTION_CONFIG_FIELDS)}
height="100%"
/>
diff --git a/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx b/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx
index 118f53aef54..b31f774d88b 100644
--- a/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx
+++ b/web-console/src/dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog.tsx
@@ -114,7 +114,13 @@ export const CoordinatorDynamicConfigDialog = React.memo(function CoordinatorDyn
.
-
+ {
+ setJsonError(undefined);
+ setCurrentTab(t);
+ }}
+ />
{currentTab === 'form' ? (
{
- setDynamicConfig(v);
- setJsonError(undefined);
- }}
- onError={setJsonError}
+ onChange={setDynamicConfig}
+ setError={setJsonError}
/>
)}
>
diff --git a/web-console/src/dialogs/index-spec-dialog/index-spec-dialog.tsx b/web-console/src/dialogs/index-spec-dialog/index-spec-dialog.tsx
index daa9e060699..5f579953d1b 100644
--- a/web-console/src/dialogs/index-spec-dialog/index-spec-dialog.tsx
+++ b/web-console/src/dialogs/index-spec-dialog/index-spec-dialog.tsx
@@ -50,22 +50,25 @@ export const IndexSpecDialog = React.memo(function IndexSpecDialog(props: IndexS
canOutsideClickClose={false}
title={title ?? 'Index spec'}
>
-
+ {
+ setJsonError(undefined);
+ setCurrentTab(t);
+ }}
+ />
{currentTab === 'form' ? (
setCurrentIndexSpec(m)}
+ onChange={setCurrentIndexSpec}
/>
) : (
{
- setCurrentIndexSpec(v);
- setJsonError(undefined);
- }}
- onError={setJsonError}
+ onChange={setCurrentIndexSpec}
+ setError={setJsonError}
issueWithValue={value => AutoForm.issueWithModel(value, INDEX_SPEC_FIELDS)}
height="100%"
/>
diff --git a/web-console/src/dialogs/lookup-edit-dialog/lookup-edit-dialog.tsx b/web-console/src/dialogs/lookup-edit-dialog/lookup-edit-dialog.tsx
index 0903ede6f96..6109dfb9219 100644
--- a/web-console/src/dialogs/lookup-edit-dialog/lookup-edit-dialog.tsx
+++ b/web-console/src/dialogs/lookup-edit-dialog/lookup-edit-dialog.tsx
@@ -121,7 +121,13 @@ export const LookupEditDialog = React.memo(function LookupEditDialog(props: Look
}
/>
-
+ {
+ setJsonError(undefined);
+ setCurrentTab(t);
+ }}
+ />
{currentTab === 'form' ? (
{
- onChange('spec', m);
- setJsonError(undefined);
- }}
- onError={setJsonError}
+ onChange={m => onChange('spec', m)}
+ setError={setJsonError}
issueWithValue={spec => AutoForm.issueWithModel(spec, LOOKUP_FIELDS)}
/>
)}
diff --git a/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx b/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx
index fa31d2378b2..109901a71b2 100644
--- a/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx
+++ b/web-console/src/dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog.tsx
@@ -114,7 +114,13 @@ export const OverlordDynamicConfigDialog = React.memo(function OverlordDynamicCo
.
-
+ {
+ setJsonError(undefined);
+ setCurrentTab(t);
+ }}
+ />
{currentTab === 'form' ? (
{
- setDynamicConfig(v);
- setJsonError(undefined);
- }}
- onError={setJsonError}
+ onChange={setDynamicConfig}
+ setError={setJsonError}
/>
)}
>
diff --git a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx
index 547fd99ee3c..64204137067 100644
--- a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx
+++ b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx
@@ -187,7 +187,7 @@ ORDER BY 1`,
)}
diff --git a/web-console/src/druid-models/async-query/async-query.ts b/web-console/src/druid-models/async-query/async-query.ts
index 401569f558b..e823ba6a17e 100644
--- a/web-console/src/druid-models/async-query/async-query.ts
+++ b/web-console/src/druid-models/async-query/async-query.ts
@@ -28,10 +28,14 @@ export interface AsyncStatusResponse {
schema?: { name: string; type: string; nativeType: string }[];
result?: {
dataSource: string;
- sampleRecords: any[][];
+ sampleRecords?: any[][];
numTotalRows: number;
totalSizeInBytes: number;
- pages: any[];
+ pages?: {
+ id: number;
+ numRows: number;
+ sizeInBytes: number;
+ }[];
};
errorDetails?: ErrorResponse;
}
diff --git a/web-console/src/druid-models/execution/execution-ingest-complete.mock.ts b/web-console/src/druid-models/execution/execution-ingest-complete.mock.ts
index 797fdd5f25c..3ae77b27ef2 100644
--- a/web-console/src/druid-models/execution/execution-ingest-complete.mock.ts
+++ b/web-console/src/druid-models/execution/execution-ingest-complete.mock.ts
@@ -43,12 +43,12 @@ PARTITIONED BY ALL TIME
export const EXECUTION_INGEST_COMPLETE = Execution.fromTaskReport({
multiStageQuery: {
type: 'multiStageQuery',
- taskId: 'query-5aa683e2-a6ee-4655-a834-a643e91055b1',
+ taskId: 'query-93a855fa-c35a-48df-b596-6bc98eed1101',
payload: {
status: {
status: 'SUCCESS',
- startTime: '2023-06-19T05:39:26.377Z',
- durationMs: 23170,
+ startTime: '2023-08-01T03:12:59.527Z',
+ durationMs: 23699,
pendingTasks: 0,
runningTasks: 2,
},
@@ -56,7 +56,7 @@ export const EXECUTION_INGEST_COMPLETE = Execution.fromTaskReport({
{
stageNumber: 0,
definition: {
- id: '8af42220-2724-4a76-b39f-c2f98df2de69_0',
+ id: 'ad318360-2ccf-4afc-b221-27c8704bf4fe_0',
input: [
{
type: 'external',
@@ -129,16 +129,17 @@ export const EXECUTION_INGEST_COMPLETE = Execution.fromTaskReport({
context: {
__timeColumn: 'v0',
__user: 'allowAll',
+ executionMode: 'async',
finalize: false,
finalizeAggregations: false,
groupByEnableMultiValueUnnesting: false,
maxNumTasks: 2,
maxParseExceptions: 0,
- queryId: '5aa683e2-a6ee-4655-a834-a643e91055b1',
+ queryId: '93a855fa-c35a-48df-b596-6bc98eed1101',
scanSignature:
'[{"name":"agent_type","type":"STRING"},{"name":"v0","type":"LONG"}]',
sqlInsertSegmentGranularity: '{"type":"all"}',
- sqlQueryId: '5aa683e2-a6ee-4655-a834-a643e91055b1',
+ sqlQueryId: '93a855fa-c35a-48df-b596-6bc98eed1101',
sqlReplaceTimeChunks: 'all',
},
granularity: {
@@ -178,14 +179,14 @@ export const EXECUTION_INGEST_COMPLETE = Execution.fromTaskReport({
phase: 'FINISHED',
workerCount: 1,
partitionCount: 1,
- startTime: '2023-06-19T05:39:26.711Z',
- duration: 20483,
+ startTime: '2023-08-01T03:12:59.865Z',
+ duration: 21324,
sort: true,
},
{
stageNumber: 1,
definition: {
- id: '8af42220-2724-4a76-b39f-c2f98df2de69_1',
+ id: 'ad318360-2ccf-4afc-b221-27c8704bf4fe_1',
input: [
{
type: 'stage',
@@ -250,8 +251,8 @@ export const EXECUTION_INGEST_COMPLETE = Execution.fromTaskReport({
phase: 'FINISHED',
workerCount: 1,
partitionCount: 1,
- startTime: '2023-06-19T05:39:47.166Z',
- duration: 2381,
+ startTime: '2023-08-01T03:13:21.156Z',
+ duration: 2070,
},
],
counters: {
@@ -314,120 +315,135 @@ export const EXECUTION_INGEST_COMPLETE = Execution.fromTaskReport({
},
},
},
-}).updateWithTaskPayload({
- task: 'query-5aa683e2-a6ee-4655-a834-a643e91055b1',
- payload: {
- type: 'query_controller',
- id: 'query-5aa683e2-a6ee-4655-a834-a643e91055b1',
- spec: {
- query: {
- queryType: 'scan',
- dataSource: {
- type: 'external',
- inputSource: {
- type: 'http',
- uris: ['https://static.imply.io/example-data/kttm-v2/kttm-v2-2019-08-25.json.gz'],
- },
- inputFormat: {
- type: 'json',
- keepNullColumns: false,
- assumeNewlineDelimited: false,
- useJsonNodeReader: false,
- },
- signature: [
- {
- name: 'timestamp',
- type: 'STRING',
+})
+ .updateWithTaskPayload({
+ task: 'query-93a855fa-c35a-48df-b596-6bc98eed1101',
+ payload: {
+ type: 'query_controller',
+ id: 'query-93a855fa-c35a-48df-b596-6bc98eed1101',
+ spec: {
+ query: {
+ queryType: 'scan',
+ dataSource: {
+ type: 'external',
+ inputSource: {
+ type: 'http',
+ uris: ['https://static.imply.io/example-data/kttm-v2/kttm-v2-2019-08-25.json.gz'],
},
+ inputFormat: {
+ type: 'json',
+ keepNullColumns: false,
+ assumeNewlineDelimited: false,
+ useJsonNodeReader: false,
+ },
+ signature: [
+ {
+ name: 'timestamp',
+ type: 'STRING',
+ },
+ {
+ name: 'agent_type',
+ type: 'STRING',
+ },
+ ],
+ },
+ intervals: {
+ type: 'intervals',
+ intervals: ['-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z'],
+ },
+ virtualColumns: [
{
- name: 'agent_type',
- type: 'STRING',
+ type: 'expression',
+ name: 'v0',
+ expression: 'timestamp_parse("timestamp",null,\'UTC\')',
+ outputType: 'LONG',
},
],
+ resultFormat: 'compactedList',
+ columns: ['agent_type', 'v0'],
+ legacy: false,
+ context: {
+ __user: 'allowAll',
+ executionMode: 'async',
+ finalize: false,
+ finalizeAggregations: false,
+ groupByEnableMultiValueUnnesting: false,
+ maxNumTasks: 2,
+ maxParseExceptions: 0,
+ queryId: '93a855fa-c35a-48df-b596-6bc98eed1101',
+ scanSignature: '[{"name":"agent_type","type":"STRING"},{"name":"v0","type":"LONG"}]',
+ sqlInsertSegmentGranularity: '{"type":"all"}',
+ sqlQueryId: '93a855fa-c35a-48df-b596-6bc98eed1101',
+ sqlReplaceTimeChunks: 'all',
+ },
+ granularity: {
+ type: 'all',
+ },
},
- intervals: {
- type: 'intervals',
- intervals: ['-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z'],
- },
- virtualColumns: [
+ columnMappings: [
{
- type: 'expression',
- name: 'v0',
- expression: 'timestamp_parse("timestamp",null,\'UTC\')',
- outputType: 'LONG',
+ queryColumn: 'v0',
+ outputColumn: '__time',
+ },
+ {
+ queryColumn: 'agent_type',
+ outputColumn: 'agent_type',
},
],
- resultFormat: 'compactedList',
- columns: ['agent_type', 'v0'],
- legacy: false,
- context: {
- __user: 'allowAll',
- finalize: false,
- finalizeAggregations: false,
- groupByEnableMultiValueUnnesting: false,
- maxNumTasks: 2,
- maxParseExceptions: 0,
- queryId: '5aa683e2-a6ee-4655-a834-a643e91055b1',
- scanSignature: '[{"name":"agent_type","type":"STRING"},{"name":"v0","type":"LONG"}]',
- sqlInsertSegmentGranularity: '{"type":"all"}',
- sqlQueryId: '5aa683e2-a6ee-4655-a834-a643e91055b1',
- sqlReplaceTimeChunks: 'all',
+ destination: {
+ type: 'dataSource',
+ dataSource: 'kttm_simple',
+ segmentGranularity: {
+ type: 'all',
+ },
+ replaceTimeChunks: ['-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z'],
},
- granularity: {
- type: 'all',
+ assignmentStrategy: 'max',
+ tuningConfig: {
+ maxNumWorkers: 1,
+ maxRowsInMemory: 100000,
+ rowsPerSegment: 3000000,
},
},
- columnMappings: [
- {
- queryColumn: 'v0',
- outputColumn: '__time',
- },
- {
- queryColumn: 'agent_type',
- outputColumn: 'agent_type',
- },
- ],
- destination: {
- type: 'dataSource',
- dataSource: 'kttm_simple',
- segmentGranularity: {
- type: 'all',
- },
- replaceTimeChunks: ['-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z'],
+ sqlQuery:
+ 'REPLACE INTO "kttm_simple" OVERWRITE ALL\nSELECT\n TIME_PARSE("timestamp") AS "__time",\n "agent_type"\nFROM TABLE(\n EXTERN(\n \'{"type":"http","uris":["https://static.imply.io/example-data/kttm-v2/kttm-v2-2019-08-25.json.gz"]}\',\n \'{"type":"json"}\'\n )\n) EXTEND ("timestamp" VARCHAR, "agent_type" VARCHAR)\nPARTITIONED BY ALL TIME',
+ sqlQueryContext: {
+ finalizeAggregations: false,
+ sqlQueryId: '93a855fa-c35a-48df-b596-6bc98eed1101',
+ groupByEnableMultiValueUnnesting: false,
+ sqlInsertSegmentGranularity: '{"type":"all"}',
+ maxNumTasks: 2,
+ sqlReplaceTimeChunks: 'all',
+ executionMode: 'async',
+ queryId: '93a855fa-c35a-48df-b596-6bc98eed1101',
},
- assignmentStrategy: 'max',
- tuningConfig: {
- maxNumWorkers: 1,
- maxRowsInMemory: 100000,
- rowsPerSegment: 3000000,
+ sqlResultsContext: {
+ timeZone: 'UTC',
+ serializeComplexValues: true,
+ stringifyArrays: true,
+ },
+ sqlTypeNames: ['TIMESTAMP', 'VARCHAR'],
+ nativeTypeNames: ['LONG', 'STRING'],
+ context: {
+ forceTimeChunkLock: true,
+ useLineageBasedSegmentAllocation: true,
+ },
+ groupId: 'query-93a855fa-c35a-48df-b596-6bc98eed1101',
+ dataSource: 'kttm_simple',
+ resource: {
+ availabilityGroup: 'query-93a855fa-c35a-48df-b596-6bc98eed1101',
+ requiredCapacity: 1,
},
},
- sqlQuery:
- 'REPLACE INTO "kttm_simple" OVERWRITE ALL\nSELECT\n TIME_PARSE("timestamp") AS "__time",\n "agent_type"\nFROM TABLE(\n EXTERN(\n \'{"type":"http","uris":["https://static.imply.io/example-data/kttm-v2/kttm-v2-2019-08-25.json.gz"]}\',\n \'{"type":"json"}\'\n )\n) EXTEND ("timestamp" VARCHAR, "agent_type" VARCHAR)\nPARTITIONED BY ALL TIME',
- sqlQueryContext: {
- finalizeAggregations: false,
- sqlQueryId: '5aa683e2-a6ee-4655-a834-a643e91055b1',
- groupByEnableMultiValueUnnesting: false,
- sqlInsertSegmentGranularity: '{"type":"all"}',
- maxNumTasks: 2,
- sqlReplaceTimeChunks: 'all',
- queryId: '5aa683e2-a6ee-4655-a834-a643e91055b1',
+ })
+ .updateWithAsyncStatus({
+ queryId: 'query-93a855fa-c35a-48df-b596-6bc98eed1101',
+ state: 'SUCCESS',
+ createdAt: '2023-08-01T03:12:50.121Z',
+ durationMs: 37657,
+ result: {
+ numTotalRows: 465346,
+ totalSizeInBytes: 0,
+ dataSource: 'kttm_simple',
},
- sqlResultsContext: {
- timeZone: 'UTC',
- serializeComplexValues: true,
- stringifyArrays: true,
- },
- sqlTypeNames: ['TIMESTAMP', 'VARCHAR'],
- context: {
- forceTimeChunkLock: true,
- useLineageBasedSegmentAllocation: true,
- },
- groupId: 'query-5aa683e2-a6ee-4655-a834-a643e91055b1',
- dataSource: 'kttm_simple',
- resource: {
- availabilityGroup: 'query-5aa683e2-a6ee-4655-a834-a643e91055b1',
- requiredCapacity: 1,
- },
- },
-});
+ });
diff --git a/web-console/src/druid-models/execution/execution-ingest-error.mock.ts b/web-console/src/druid-models/execution/execution-ingest-error.mock.ts
index 15715a1a0e0..9d58a7e558c 100644
--- a/web-console/src/druid-models/execution/execution-ingest-error.mock.ts
+++ b/web-console/src/druid-models/execution/execution-ingest-error.mock.ts
@@ -44,12 +44,12 @@ PARTITIONED BY DAY
export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
multiStageQuery: {
type: 'multiStageQuery',
- taskId: 'query-8f889312-e989-4b4c-9895-485a1fe796d3',
+ taskId: 'query-af8a263d-213f-418e-ad8d-37d55beff59b',
payload: {
status: {
status: 'FAILED',
errorReport: {
- taskId: 'query-8f889312-e989-4b4c-9895-485a1fe796d3-worker0_0',
+ taskId: 'query-af8a263d-213f-418e-ad8d-37d55beff59b-worker0_0',
host: 'localhost',
error: {
errorCode: 'TooManyWarnings',
@@ -60,7 +60,7 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
},
warnings: [
{
- taskId: 'query-8f889312-e989-4b4c-9895-485a1fe796d3-worker0_0',
+ taskId: 'query-af8a263d-213f-418e-ad8d-37d55beff59b-worker0_0',
host: 'localhost:8101',
stageNumber: 0,
error: {
@@ -69,10 +69,10 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
'Unable to parse row [] (Path: https://static.imply.io/example-data/kttm-with-issues/kttm-blank-lines.json, Record: 3, Line: 3)',
},
exceptionStackTrace:
- 'org.apache.druid.java.util.common.parsers.ParseException: Unable to parse row [] (Path: https://static.imply.io/example-data/kttm-with-issues/kttm-blank-lines.json, Record: 3, Line: 3)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:79)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.findNextIteratorIfNecessary(CloseableIterator.java:74)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.next(CloseableIterator.java:108)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$1.next(CloseableIterator.java:52)\n\tat org.apache.druid.msq.input.external.ExternalInputSliceReader$1$1.hasNext(ExternalInputSliceReader.java:183)\n\tat org.apache.druid.java.util.common.guava.BaseSequence$1.next(BaseSequence.java:115)\n\tat org.apache.druid.segment.RowWalker.advance(RowWalker.java:70)\n\tat org.apache.druid.segment.RowBasedCursor.advanceUninterruptibly(RowBasedCursor.java:110)\n\tat org.apache.druid.segment.RowBasedCursor.advance(RowBasedCursor.java:103)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeeded(ScanQueryFrameProcessor.java:246)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runWithSegment(ScanQueryFrameProcessor.java:173)\n\tat org.apache.druid.msq.querykit.BaseLeafFrameProcessor.runIncrementally(BaseLeafFrameProcessor.java:159)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runIncrementally(ScanQueryFrameProcessor.java:138)\n\tat org.apache.druid.frame.processor.FrameProcessors$1FrameProcessorWithBaggage.runIncrementally(FrameProcessors.java:75)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.runProcessorNow(FrameProcessorExecutor.java:229)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.run(FrameProcessorExecutor.java:137)\n\tat org.apache.druid.msq.exec.WorkerImpl$1$2.run(WorkerImpl.java:820)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\n\tat org.apache.druid.query.PrioritizedListenableFutureTask.run(PrioritizedExecutorService.java:251)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat java.base/java.lang.Thread.run(Thread.java:829)\nCaused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input\n at [Source: (String)""; line: 1, column: 0]\n\tat com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)\n\tat com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4360)\n\tat com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4205)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:75)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:48)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:71)\n\t... 22 more\n',
+ 'org.apache.druid.java.util.common.parsers.ParseException: Unable to parse row [] (Path: https://static.imply.io/example-data/kttm-with-issues/kttm-blank-lines.json, Record: 3, Line: 3)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:79)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.findNextIteratorIfNecessary(CloseableIterator.java:74)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.next(CloseableIterator.java:108)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$1.next(CloseableIterator.java:52)\n\tat org.apache.druid.msq.input.external.ExternalSegment$1$1.hasNext(ExternalSegment.java:95)\n\tat org.apache.druid.java.util.common.guava.BaseSequence$1.next(BaseSequence.java:115)\n\tat org.apache.druid.segment.RowWalker.advance(RowWalker.java:70)\n\tat org.apache.druid.segment.RowBasedCursor.advanceUninterruptibly(RowBasedCursor.java:110)\n\tat org.apache.druid.segment.RowBasedCursor.advance(RowBasedCursor.java:103)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeeded(ScanQueryFrameProcessor.java:275)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeededWithExceptionHandling(ScanQueryFrameProcessor.java:242)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runWithSegment(ScanQueryFrameProcessor.java:181)\n\tat org.apache.druid.msq.querykit.BaseLeafFrameProcessor.runIncrementally(BaseLeafFrameProcessor.java:159)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runIncrementally(ScanQueryFrameProcessor.java:146)\n\tat org.apache.druid.frame.processor.FrameProcessors$1FrameProcessorWithBaggage.runIncrementally(FrameProcessors.java:75)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.runProcessorNow(FrameProcessorExecutor.java:229)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.run(FrameProcessorExecutor.java:137)\n\tat org.apache.druid.msq.exec.WorkerImpl$1$2.run(WorkerImpl.java:837)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\n\tat org.apache.druid.query.PrioritizedListenableFutureTask.run(PrioritizedExecutorService.java:251)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat java.base/java.lang.Thread.run(Thread.java:829)\nCaused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input\n at [Source: (String)""; line: 1, column: 0]\n\tat com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)\n\tat com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4360)\n\tat com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4205)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:75)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:48)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:71)\n\t... 23 more\n',
},
{
- taskId: 'query-8f889312-e989-4b4c-9895-485a1fe796d3-worker0_0',
+ taskId: 'query-af8a263d-213f-418e-ad8d-37d55beff59b-worker0_0',
host: 'localhost:8101',
stageNumber: 0,
error: {
@@ -81,11 +81,11 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
'Unable to parse row [] (Path: https://static.imply.io/example-data/kttm-with-issues/kttm-blank-lines.json, Record: 6, Line: 7)',
},
exceptionStackTrace:
- 'org.apache.druid.java.util.common.parsers.ParseException: Unable to parse row [] (Path: https://static.imply.io/example-data/kttm-with-issues/kttm-blank-lines.json, Record: 6, Line: 7)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:79)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.findNextIteratorIfNecessary(CloseableIterator.java:74)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.next(CloseableIterator.java:108)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$1.next(CloseableIterator.java:52)\n\tat org.apache.druid.msq.input.external.ExternalInputSliceReader$1$1.hasNext(ExternalInputSliceReader.java:183)\n\tat org.apache.druid.java.util.common.guava.BaseSequence$1.next(BaseSequence.java:115)\n\tat org.apache.druid.segment.RowWalker.advance(RowWalker.java:70)\n\tat org.apache.druid.segment.RowBasedCursor.advanceUninterruptibly(RowBasedCursor.java:110)\n\tat org.apache.druid.segment.RowBasedCursor.advance(RowBasedCursor.java:103)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeeded(ScanQueryFrameProcessor.java:246)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runWithSegment(ScanQueryFrameProcessor.java:173)\n\tat org.apache.druid.msq.querykit.BaseLeafFrameProcessor.runIncrementally(BaseLeafFrameProcessor.java:159)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runIncrementally(ScanQueryFrameProcessor.java:138)\n\tat org.apache.druid.frame.processor.FrameProcessors$1FrameProcessorWithBaggage.runIncrementally(FrameProcessors.java:75)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.runProcessorNow(FrameProcessorExecutor.java:229)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.run(FrameProcessorExecutor.java:137)\n\tat org.apache.druid.msq.exec.WorkerImpl$1$2.run(WorkerImpl.java:820)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\n\tat org.apache.druid.query.PrioritizedListenableFutureTask.run(PrioritizedExecutorService.java:251)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat java.base/java.lang.Thread.run(Thread.java:829)\nCaused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input\n at [Source: (String)""; line: 1, column: 0]\n\tat com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)\n\tat com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4360)\n\tat com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4205)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:75)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:48)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:71)\n\t... 22 more\n',
+ 'org.apache.druid.java.util.common.parsers.ParseException: Unable to parse row [] (Path: https://static.imply.io/example-data/kttm-with-issues/kttm-blank-lines.json, Record: 6, Line: 7)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:79)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.findNextIteratorIfNecessary(CloseableIterator.java:74)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$2.next(CloseableIterator.java:108)\n\tat org.apache.druid.java.util.common.parsers.CloseableIterator$1.next(CloseableIterator.java:52)\n\tat org.apache.druid.msq.input.external.ExternalSegment$1$1.hasNext(ExternalSegment.java:95)\n\tat org.apache.druid.java.util.common.guava.BaseSequence$1.next(BaseSequence.java:115)\n\tat org.apache.druid.segment.RowWalker.advance(RowWalker.java:70)\n\tat org.apache.druid.segment.RowBasedCursor.advanceUninterruptibly(RowBasedCursor.java:110)\n\tat org.apache.druid.segment.RowBasedCursor.advance(RowBasedCursor.java:103)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeeded(ScanQueryFrameProcessor.java:275)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.populateFrameWriterAndFlushIfNeededWithExceptionHandling(ScanQueryFrameProcessor.java:242)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runWithSegment(ScanQueryFrameProcessor.java:181)\n\tat org.apache.druid.msq.querykit.BaseLeafFrameProcessor.runIncrementally(BaseLeafFrameProcessor.java:159)\n\tat org.apache.druid.msq.querykit.scan.ScanQueryFrameProcessor.runIncrementally(ScanQueryFrameProcessor.java:146)\n\tat org.apache.druid.frame.processor.FrameProcessors$1FrameProcessorWithBaggage.runIncrementally(FrameProcessors.java:75)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.runProcessorNow(FrameProcessorExecutor.java:229)\n\tat org.apache.druid.frame.processor.FrameProcessorExecutor$1ExecutorRunnable.run(FrameProcessorExecutor.java:137)\n\tat org.apache.druid.msq.exec.WorkerImpl$1$2.run(WorkerImpl.java:837)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)\n\tat org.apache.druid.query.PrioritizedListenableFutureTask.run(PrioritizedExecutorService.java:251)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\n\tat java.base/java.lang.Thread.run(Thread.java:829)\nCaused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input\n at [Source: (String)""; line: 1, column: 0]\n\tat com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)\n\tat com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4360)\n\tat com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4205)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214)\n\tat com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:75)\n\tat org.apache.druid.data.input.impl.JsonLineReader.parseInputRows(JsonLineReader.java:48)\n\tat org.apache.druid.data.input.IntermediateRowParsingReader$1.hasNext(IntermediateRowParsingReader.java:71)\n\t... 23 more\n',
},
],
- startTime: '2023-06-19T05:37:48.605Z',
- durationMs: 14760,
+ startTime: '2023-08-01T04:20:24.945Z',
+ durationMs: 14545,
pendingTasks: 0,
runningTasks: 2,
},
@@ -93,7 +93,7 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
{
stageNumber: 0,
definition: {
- id: 'd337a3d8-e361-4795-8eaa-97ced72d9a7b_0',
+ id: 'f635e36d-6b90-4b74-ad5e-a179c99f0ddc_0',
input: [
{
type: 'external',
@@ -168,16 +168,17 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
context: {
__timeColumn: 'v0',
__user: 'allowAll',
+ executionMode: 'async',
finalize: false,
finalizeAggregations: false,
groupByEnableMultiValueUnnesting: false,
maxNumTasks: 2,
maxParseExceptions: 2,
- queryId: '8f889312-e989-4b4c-9895-485a1fe796d3',
+ queryId: 'af8a263d-213f-418e-ad8d-37d55beff59b',
scanSignature:
'[{"name":"agent_type","type":"STRING"},{"name":"v0","type":"LONG"}]',
sqlInsertSegmentGranularity: '"DAY"',
- sqlQueryId: '8f889312-e989-4b4c-9895-485a1fe796d3',
+ sqlQueryId: 'af8a263d-213f-418e-ad8d-37d55beff59b',
sqlReplaceTimeChunks: 'all',
},
granularity: {
@@ -225,14 +226,14 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
},
phase: 'FAILED',
workerCount: 1,
- startTime: '2023-06-19T05:37:48.952Z',
- duration: 14412,
+ startTime: '2023-08-01T04:20:25.296Z',
+ duration: 14193,
sort: true,
},
{
stageNumber: 1,
definition: {
- id: 'd337a3d8-e361-4795-8eaa-97ced72d9a7b_1',
+ id: 'f635e36d-6b90-4b74-ad5e-a179c99f0ddc_1',
input: [
{
type: 'stage',
@@ -334,10 +335,10 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
},
},
}).updateWithTaskPayload({
- task: 'query-8f889312-e989-4b4c-9895-485a1fe796d3',
+ task: 'query-af8a263d-213f-418e-ad8d-37d55beff59b',
payload: {
type: 'query_controller',
- id: 'query-8f889312-e989-4b4c-9895-485a1fe796d3',
+ id: 'query-af8a263d-213f-418e-ad8d-37d55beff59b',
spec: {
query: {
queryType: 'scan',
@@ -381,15 +382,16 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
legacy: false,
context: {
__user: 'allowAll',
+ executionMode: 'async',
finalize: false,
finalizeAggregations: false,
groupByEnableMultiValueUnnesting: false,
maxNumTasks: 2,
maxParseExceptions: 2,
- queryId: '8f889312-e989-4b4c-9895-485a1fe796d3',
+ queryId: 'af8a263d-213f-418e-ad8d-37d55beff59b',
scanSignature: '[{"name":"agent_type","type":"STRING"},{"name":"v0","type":"LONG"}]',
sqlInsertSegmentGranularity: '"DAY"',
- sqlQueryId: '8f889312-e989-4b4c-9895-485a1fe796d3',
+ sqlQueryId: 'af8a263d-213f-418e-ad8d-37d55beff59b',
sqlReplaceTimeChunks: 'all',
},
granularity: {
@@ -424,12 +426,13 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
sqlQueryContext: {
maxParseExceptions: 2,
finalizeAggregations: false,
- sqlQueryId: '8f889312-e989-4b4c-9895-485a1fe796d3',
+ sqlQueryId: 'af8a263d-213f-418e-ad8d-37d55beff59b',
groupByEnableMultiValueUnnesting: false,
sqlInsertSegmentGranularity: '"DAY"',
maxNumTasks: 2,
sqlReplaceTimeChunks: 'all',
- queryId: '8f889312-e989-4b4c-9895-485a1fe796d3',
+ executionMode: 'async',
+ queryId: 'af8a263d-213f-418e-ad8d-37d55beff59b',
},
sqlResultsContext: {
timeZone: 'UTC',
@@ -437,14 +440,15 @@ export const EXECUTION_INGEST_ERROR = Execution.fromTaskReport({
stringifyArrays: true,
},
sqlTypeNames: ['TIMESTAMP', 'VARCHAR'],
+ nativeTypeNames: ['LONG', 'STRING'],
context: {
forceTimeChunkLock: true,
useLineageBasedSegmentAllocation: true,
},
- groupId: 'query-8f889312-e989-4b4c-9895-485a1fe796d3',
+ groupId: 'query-af8a263d-213f-418e-ad8d-37d55beff59b',
dataSource: 'kttm-blank-lines',
resource: {
- availabilityGroup: 'query-8f889312-e989-4b4c-9895-485a1fe796d3',
+ availabilityGroup: 'query-af8a263d-213f-418e-ad8d-37d55beff59b',
requiredCapacity: 1,
},
},
diff --git a/web-console/src/druid-models/execution/execution.spec.ts b/web-console/src/druid-models/execution/execution.spec.ts
index dd7833c635e..a6b55db6808 100644
--- a/web-console/src/druid-models/execution/execution.spec.ts
+++ b/web-console/src/druid-models/execution/execution.spec.ts
@@ -42,10 +42,14 @@ describe('Execution', () => {
"useLineageBasedSegmentAllocation": true,
},
"dataSource": "kttm_simple",
- "groupId": "query-5aa683e2-a6ee-4655-a834-a643e91055b1",
- "id": "query-5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "groupId": "query-93a855fa-c35a-48df-b596-6bc98eed1101",
+ "id": "query-93a855fa-c35a-48df-b596-6bc98eed1101",
+ "nativeTypeNames": Array [
+ "LONG",
+ "STRING",
+ ],
"resource": Object {
- "availabilityGroup": "query-5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "availabilityGroup": "query-93a855fa-c35a-48df-b596-6bc98eed1101",
"requiredCapacity": 1,
},
"spec": Object {
@@ -77,15 +81,16 @@ describe('Execution', () => {
],
"context": Object {
"__user": "allowAll",
+ "executionMode": "async",
"finalize": false,
"finalizeAggregations": false,
"groupByEnableMultiValueUnnesting": false,
"maxNumTasks": 2,
"maxParseExceptions": 0,
- "queryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "queryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"scanSignature": "[{\\"name\\":\\"agent_type\\",\\"type\\":\\"STRING\\"},{\\"name\\":\\"v0\\",\\"type\\":\\"LONG\\"}]",
"sqlInsertSegmentGranularity": "{\\"type\\":\\"all\\"}",
- "sqlQueryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "sqlQueryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"sqlReplaceTimeChunks": "all",
},
"dataSource": Object {
@@ -152,12 +157,13 @@ describe('Execution', () => {
) EXTEND (\\"timestamp\\" VARCHAR, \\"agent_type\\" VARCHAR)
PARTITIONED BY ALL TIME",
"sqlQueryContext": Object {
+ "executionMode": "async",
"finalizeAggregations": false,
"groupByEnableMultiValueUnnesting": false,
"maxNumTasks": 2,
- "queryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "queryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"sqlInsertSegmentGranularity": "{\\"type\\":\\"all\\"}",
- "sqlQueryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "sqlQueryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"sqlReplaceTimeChunks": "all",
},
"sqlResultsContext": Object {
@@ -171,11 +177,12 @@ describe('Execution', () => {
],
"type": "query_controller",
},
- "task": "query-5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "task": "query-93a855fa-c35a-48df-b596-6bc98eed1101",
},
"capacityInfo": undefined,
"destination": Object {
"dataSource": "kttm_simple",
+ "numTotalRows": 465346,
"replaceTimeChunks": Array [
"-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z",
],
@@ -184,10 +191,11 @@ describe('Execution', () => {
},
"type": "dataSource",
},
- "duration": 23170,
+ "destinationPages": undefined,
+ "duration": 23699,
"engine": "sql-msq-task",
"error": undefined,
- "id": "query-5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "id": "query-93a855fa-c35a-48df-b596-6bc98eed1101",
"nativeQuery": Object {
"columns": Array [
"agent_type",
@@ -195,15 +203,16 @@ describe('Execution', () => {
],
"context": Object {
"__user": "allowAll",
+ "executionMode": "async",
"finalize": false,
"finalizeAggregations": false,
"groupByEnableMultiValueUnnesting": false,
"maxNumTasks": 2,
"maxParseExceptions": 0,
- "queryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "queryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"scanSignature": "[{\\"name\\":\\"agent_type\\",\\"type\\":\\"STRING\\"},{\\"name\\":\\"v0\\",\\"type\\":\\"LONG\\"}]",
"sqlInsertSegmentGranularity": "{\\"type\\":\\"all\\"}",
- "sqlQueryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "sqlQueryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"sqlReplaceTimeChunks": "all",
},
"dataSource": Object {
@@ -253,6 +262,7 @@ describe('Execution', () => {
],
},
"queryContext": Object {
+ "executionMode": "async",
"finalizeAggregations": false,
"groupByEnableMultiValueUnnesting": false,
"maxNumTasks": 2,
@@ -357,7 +367,7 @@ describe('Execution', () => {
"stages": Array [
Object {
"definition": Object {
- "id": "8af42220-2724-4a76-b39f-c2f98df2de69_0",
+ "id": "ad318360-2ccf-4afc-b221-27c8704bf4fe_0",
"input": Array [
Object {
"inputFormat": Object {
@@ -395,15 +405,16 @@ describe('Execution', () => {
"context": Object {
"__timeColumn": "v0",
"__user": "allowAll",
+ "executionMode": "async",
"finalize": false,
"finalizeAggregations": false,
"groupByEnableMultiValueUnnesting": false,
"maxNumTasks": 2,
"maxParseExceptions": 0,
- "queryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "queryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"scanSignature": "[{\\"name\\":\\"agent_type\\",\\"type\\":\\"STRING\\"},{\\"name\\":\\"v0\\",\\"type\\":\\"LONG\\"}]",
"sqlInsertSegmentGranularity": "{\\"type\\":\\"all\\"}",
- "sqlQueryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "sqlQueryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"sqlReplaceTimeChunks": "all",
},
"dataSource": Object {
@@ -482,17 +493,17 @@ describe('Execution', () => {
},
],
},
- "duration": 20483,
+ "duration": 21324,
"partitionCount": 1,
"phase": "FINISHED",
"sort": true,
"stageNumber": 0,
- "startTime": "2023-06-19T05:39:26.711Z",
+ "startTime": "2023-08-01T03:12:59.865Z",
"workerCount": 1,
},
Object {
"definition": Object {
- "id": "8af42220-2724-4a76-b39f-c2f98df2de69_1",
+ "id": "ad318360-2ccf-4afc-b221-27c8704bf4fe_1",
"input": Array [
Object {
"stage": 0,
@@ -558,16 +569,16 @@ describe('Execution', () => {
},
"signature": Array [],
},
- "duration": 2381,
+ "duration": 2070,
"partitionCount": 1,
"phase": "FINISHED",
"stageNumber": 1,
- "startTime": "2023-06-19T05:39:47.166Z",
+ "startTime": "2023-08-01T03:13:21.156Z",
"workerCount": 1,
},
],
},
- "startTime": 2023-06-19T05:39:26.377Z,
+ "startTime": 2023-08-01T03:12:59.527Z,
"status": "SUCCESS",
"usageInfo": Object {
"pendingTasks": 0,
@@ -586,8 +597,16 @@ describe('Execution', () => {
"_payload": undefined,
"capacityInfo": undefined,
"destination": Object {
+ "numTotalRows": 2,
"type": "taskReport",
},
+ "destinationPages": Array [
+ Object {
+ "id": 0,
+ "numRows": 2,
+ "sizeInBytes": 116,
+ },
+ ],
"duration": 29168,
"engine": "sql-msq-task",
"error": undefined,
@@ -640,6 +659,7 @@ describe('Execution', () => {
"_payload": undefined,
"capacityInfo": undefined,
"destination": undefined,
+ "destinationPages": undefined,
"duration": 11217,
"engine": "sql-msq-task",
"error": Object {
diff --git a/web-console/src/druid-models/execution/execution.ts b/web-console/src/druid-models/execution/execution.ts
index b64ba19548a..8f30711b283 100644
--- a/web-console/src/druid-models/execution/execution.ts
+++ b/web-console/src/druid-models/execution/execution.ts
@@ -31,12 +31,7 @@ import type { DruidEngine } from '../druid-engine/druid-engine';
import { validDruidEngine } from '../druid-engine/druid-engine';
import type { QueryContext } from '../query-context/query-context';
import { Stages } from '../stages/stages';
-import type {
- MsqTaskPayloadResponse,
- MsqTaskReportResponse,
- TaskStatus,
- TaskStatusResponse,
-} from '../task/task';
+import type { MsqTaskPayloadResponse, MsqTaskReportResponse, TaskStatus } from '../task/task';
const IGNORE_CONTEXT_KEYS = [
'__asyncIdentity__',
@@ -70,12 +65,19 @@ export interface ExecutionError {
exceptionStackTrace?: string;
}
-type ExecutionDestination =
+export type ExecutionDestination =
| {
type: 'taskReport';
+ numTotalRows?: number;
}
- | { type: 'dataSource'; dataSource: string; numRows?: number; loaded?: boolean }
- | { type: 'download' };
+ | { type: 'durableStorage'; numTotalRows?: number }
+ | { type: 'dataSource'; dataSource: string; numTotalRows?: number; loaded?: boolean };
+
+export interface ExecutionDestinationPage {
+ id: number;
+ numRows: number;
+ sizeInBytes: number;
+}
export type ExecutionStatus = 'RUNNING' | 'FAILED' | 'SUCCESS';
@@ -174,6 +176,7 @@ export interface ExecutionValue {
usageInfo?: UsageInfo;
stages?: Stages;
destination?: ExecutionDestination;
+ destinationPages?: ExecutionDestinationPage[];
result?: QueryResult;
error?: ExecutionError;
warnings?: ExecutionError[];
@@ -214,38 +217,6 @@ export class Execution {
}
}
- static fromTaskSubmit(
- taskSubmitResult: { state: any; taskId: string; error: any },
- sqlQuery?: string,
- queryContext?: QueryContext,
- ): Execution {
- const status = Execution.normalizeTaskStatus(taskSubmitResult.state);
- return new Execution({
- engine: 'sql-msq-task',
- id: taskSubmitResult.taskId,
- status: taskSubmitResult.error ? 'FAILED' : status,
- sqlQuery,
- queryContext,
- error: taskSubmitResult.error
- ? {
- error: {
- errorCode: 'AsyncError',
- errorMessage: JSON.stringify(taskSubmitResult.error),
- },
- }
- : status === 'FAILED'
- ? {
- error: {
- errorCode: 'UnknownError',
- errorMessage:
- 'Execution failed, there is no detail information, and there is no error in the status response',
- },
- }
- : undefined,
- destination: undefined,
- });
- }
-
static fromAsyncStatus(
asyncSubmitResult: AsyncStatusResponse,
sqlQuery?: string,
@@ -286,49 +257,18 @@ export class Execution {
? {
type: 'dataSource',
dataSource: result.dataSource,
- numRows: result.numTotalRows,
+ numTotalRows: result.numTotalRows,
}
: {
type: 'taskReport',
+ numTotalRows: result.numTotalRows,
}
: undefined,
+ destinationPages: result?.pages,
result: queryResult,
});
}
- static fromTaskStatus(
- taskStatus: TaskStatusResponse,
- sqlQuery?: string,
- queryContext?: QueryContext,
- ): Execution {
- const status = Execution.normalizeTaskStatus(taskStatus.status.status);
- return new Execution({
- engine: 'sql-msq-task',
- id: taskStatus.task,
- status: taskStatus.status.error ? 'FAILED' : status,
- usageInfo: getUsageInfoFromStatusPayload(taskStatus.status),
- sqlQuery,
- queryContext,
- error: taskStatus.status.error
- ? {
- error: {
- errorCode: 'AsyncError',
- errorMessage: JSON.stringify(taskStatus.status.error),
- },
- }
- : status === 'FAILED'
- ? {
- error: {
- errorCode: 'UnknownError',
- errorMessage:
- 'Execution failed, there is no detail information, and there is no error in the status response',
- },
- }
- : undefined,
- destination: undefined,
- });
- }
-
static fromTaskReport(taskReport: MsqTaskReportResponse): Execution {
// Must have status set for a valid report
const id = deepGet(taskReport, 'multiStageQuery.taskId');
@@ -424,6 +364,7 @@ export class Execution {
public readonly usageInfo?: UsageInfo;
public readonly stages?: Stages;
public readonly destination?: ExecutionDestination;
+ public readonly destinationPages?: ExecutionDestinationPage[];
public readonly result?: QueryResult;
public readonly error?: ExecutionError;
public readonly warnings?: ExecutionError[];
@@ -444,6 +385,7 @@ export class Execution {
this.usageInfo = value.usageInfo;
this.stages = value.stages;
this.destination = value.destination;
+ this.destinationPages = value.destinationPages;
this.result = value.result;
this.error = value.error;
this.warnings = nonEmptyArray(value.warnings) ? value.warnings : undefined;
@@ -465,6 +407,7 @@ export class Execution {
usageInfo: this.usageInfo,
stages: this.stages,
destination: this.destination,
+ destinationPages: this.destinationPages,
result: this.result,
error: this.error,
warnings: this.warnings,
@@ -494,6 +437,13 @@ export class Execution {
});
}
+ public changeDestinationPages(destinationPages: ExecutionDestinationPage[]): Execution {
+ return new Execution({
+ ...this.valueOf(),
+ destinationPages,
+ });
+ }
+
public changeResult(result: QueryResult): Execution {
return new Execution({
...this.valueOf(),
@@ -514,7 +464,7 @@ export class Execution {
value._payload = taskPayload;
value.destination = {
...value.destination,
- ...(deepGet(taskPayload, 'payload.spec.destination') || {}),
+ ...deepGet(taskPayload, 'payload.spec.destination'),
};
value.nativeQuery = deepGet(taskPayload, 'payload.spec.query');
@@ -530,18 +480,23 @@ export class Execution {
return ret;
}
- public attachErrorFromStatus(status: any): Execution {
- const errorMsg = deepGet(status, 'status.errorMsg');
+ public updateWithAsyncStatus(statusPayload: AsyncStatusResponse): Execution {
+ const value = this.valueOf();
- return new Execution({
- ...this.valueOf(),
- error: {
- error: {
- errorCode: 'UnknownError',
- errorMessage: errorMsg,
- },
- },
- });
+ const { pages, numTotalRows } = statusPayload.result || {};
+
+ if (!value.destinationPages && pages) {
+ value.destinationPages = pages;
+ }
+
+ if (typeof value.destination?.numTotalRows !== 'number' && typeof numTotalRows === 'number') {
+ value.destination = {
+ ...(value.destination || { type: 'taskReport' }),
+ numTotalRows,
+ };
+ }
+
+ return new Execution(value);
}
public markDestinationDatasourceLoaded(): Execution {
@@ -588,20 +543,8 @@ export class Execution {
return destination.dataSource;
}
- public getIngestNumRows(): number | undefined {
- const { destination, stages } = this;
-
- if (destination?.type === 'dataSource' && typeof destination.numRows === 'number') {
- return destination.numRows;
- }
-
- const lastStage = stages?.getLastStage();
- if (stages && lastStage && lastStage.definition.processor.type === 'segmentGenerator') {
- // Assume input0 since we know the segmentGenerator will only ever have one stage input
- return stages.getTotalCounterForStage(lastStage, 'input0', 'rows');
- }
-
- return;
+ public getOutputNumTotalRows(): number | undefined {
+ return this.destination?.numTotalRows;
}
public isSuccessfulInsert(): boolean {
diff --git a/web-console/src/druid-models/task/task.ts b/web-console/src/druid-models/task/task.ts
index 65dbb62c065..8f6f456ccb4 100644
--- a/web-console/src/druid-models/task/task.ts
+++ b/web-console/src/druid-models/task/task.ts
@@ -66,6 +66,7 @@ export interface MsqTaskPayloadResponse {
sqlQueryContext: Record;
sqlResultsContext: Record;
sqlTypeNames: string[];
+ nativeTypeNames: string[];
context: Record;
groupId: string;
dataSource: string;
diff --git a/web-console/src/helpers/execution/sql-task-execution.ts b/web-console/src/helpers/execution/sql-task-execution.ts
index 79e28e486d3..1643e8a076d 100644
--- a/web-console/src/helpers/execution/sql-task-execution.ts
+++ b/web-console/src/helpers/execution/sql-task-execution.ts
@@ -19,7 +19,7 @@
import { L, QueryResult } from '@druid-toolkit/query';
import type { AxiosResponse, CancelToken } from 'axios';
-import type { AsyncStatusResponse, QueryContext } from '../../druid-models';
+import type { AsyncStatusResponse, MsqTaskPayloadResponse, QueryContext } from '../../druid-models';
import { Execution } from '../../druid-models';
import { Api } from '../../singletons';
import {
@@ -48,7 +48,6 @@ function ensureExecutionModeIsSet(context: QueryContext | undefined): QueryConte
export interface SubmitTaskQueryOptions {
query: string | Record;
context?: QueryContext;
- skipResults?: boolean;
prefixLines?: number;
cancelToken?: CancelToken;
preserveOnTermination?: boolean;
@@ -58,15 +57,7 @@ export interface SubmitTaskQueryOptions {
export async function submitTaskQuery(
options: SubmitTaskQueryOptions,
): Promise> {
- const {
- query,
- context,
- skipResults,
- prefixLines,
- cancelToken,
- preserveOnTermination,
- onSubmitted,
- } = options;
+ const { query, context, prefixLines, cancelToken, preserveOnTermination, onSubmitted } = options;
let sqlQuery: string;
let jsonQuery: Record;
@@ -123,10 +114,6 @@ export async function submitTaskQuery(
onSubmitted(execution.id);
}
- if (skipResults) {
- execution = execution.changeDestination({ type: 'download' });
- }
-
execution = await updateExecutionWithDatasourceLoadedIfNeeded(execution, cancelToken);
if (execution.isFullyComplete()) return execution;
@@ -178,7 +165,7 @@ export async function updateExecutionWithTaskIfNeeded(
export async function getTaskExecution(
id: string,
- taskPayloadOverride?: { payload: any; task: string },
+ taskPayloadOverride?: MsqTaskPayloadResponse,
cancelToken?: CancelToken,
): Promise {
const encodedId = Api.encodePath(id);
@@ -221,7 +208,7 @@ export async function getTaskExecution(
execution = Execution.fromAsyncStatus(statusResp.data);
}
- let taskPayload: any = taskPayloadOverride;
+ let taskPayload = taskPayloadOverride;
if (USE_TASK_PAYLOAD && !taskPayload) {
try {
taskPayload = (
@@ -237,6 +224,18 @@ export async function getTaskExecution(
execution = execution.updateWithTaskPayload(taskPayload);
}
+ // Still have to pull the destination page info from the async status
+ if (execution.status === 'SUCCESS' && !execution.destinationPages) {
+ const statusResp = await Api.instance.get(
+ `/druid/v2/sql/statements/${encodedId}`,
+ {
+ cancelToken,
+ },
+ );
+
+ execution = execution.updateWithAsyncStatus(statusResp.data);
+ }
+
if (execution.hasPotentiallyStuckStage()) {
const capacityInfo = await maybeGetClusterCapacity();
if (capacityInfo) {
diff --git a/web-console/src/utils/download-query-detail-archive.ts b/web-console/src/utils/download-query-detail-archive.ts
index cb4dcb818b6..124b322c5fb 100644
--- a/web-console/src/utils/download-query-detail-archive.ts
+++ b/web-console/src/utils/download-query-detail-archive.ts
@@ -22,35 +22,39 @@ import { Api } from '../singletons';
import { downloadFile } from './download';
-interface QueryDetailArchive {
+export interface QueryDetailArchive {
id: string;
detailArchiveVersion: number;
status?: any;
reports?: any;
payload?: any;
+ statementsStatus?: any;
serverStatus?: any;
}
export async function downloadQueryDetailArchive(id: string) {
+ const encodedId = Api.encodePath(id);
const profile: QueryDetailArchive = {
id,
detailArchiveVersion: 2,
};
try {
- profile.status = (
- await Api.instance.get(`/druid/indexer/v1/task/${Api.encodePath(id)}/status`)
- ).data;
+ profile.status = (await Api.instance.get(`/druid/indexer/v1/task/${encodedId}/status`)).data;
} catch {}
try {
- profile.reports = (
- await Api.instance.get(`/druid/indexer/v1/task/${Api.encodePath(id)}/reports`)
- ).data;
+ profile.reports = (await Api.instance.get(`/druid/indexer/v1/task/${encodedId}/reports`)).data;
} catch {}
try {
- profile.payload = (await Api.instance.get(`/druid/indexer/v1/task/${Api.encodePath(id)}`)).data;
+ profile.payload = (await Api.instance.get(`/druid/indexer/v1/task/${encodedId}`)).data;
+ } catch {}
+
+ try {
+ profile.statementsStatus = (
+ await Api.instance.get(`/druid/v2/sql/statements/${encodedId}`)
+ ).data;
} catch {}
try {
diff --git a/web-console/src/utils/download.ts b/web-console/src/utils/download.ts
index 03705ee3b85..41c558edc02 100644
--- a/web-console/src/utils/download.ts
+++ b/web-console/src/utils/download.ts
@@ -22,6 +22,23 @@ import * as JSONBig from 'json-bigint-native';
import { stringifyValue } from './general';
+export function downloadUrl(url: string, filename: string) {
+ // Create a link and set the URL using `createObjectURL`
+ const link = document.createElement('a');
+ link.style.display = 'none';
+ link.href = url;
+ link.download = filename;
+ document.body.appendChild(link);
+ link.click();
+
+ // To make this work on Firefox we need to wait
+ // a little while before removing it.
+ setTimeout(() => {
+ if (!link.parentNode) return;
+ link.parentNode.removeChild(link);
+ }, 0);
+}
+
export function formatForFormat(s: null | string | number | Date, format: 'csv' | 'tsv'): string {
// stringify and remove line break
const str = stringifyValue(s).replace(/(?:\r\n|\r|\n)/g, ' ');
diff --git a/web-console/src/utils/general.tsx b/web-console/src/utils/general.tsx
index e9b8e8f2c1a..4d821ae0539 100644
--- a/web-console/src/utils/general.tsx
+++ b/web-console/src/utils/general.tsx
@@ -302,8 +302,21 @@ export function formatDurationHybrid(ms: NumberLike): string {
}
}
+function pluralize(word: string): string {
+ // Ignoring irregular plurals.
+ if (/(s|x|z|ch|sh)$/.test(word)) {
+ return word + 'es';
+ } else if (/([^aeiou])y$/.test(word)) {
+ return word.slice(0, -1) + 'ies';
+ } else if (/(f|fe)$/.test(word)) {
+ return word.replace(/fe?$/, 'ves');
+ } else {
+ return word + 's';
+ }
+}
+
export function pluralIfNeeded(n: NumberLike, singular: string, plural?: string): string {
- if (!plural) plural = singular + 's';
+ if (!plural) plural = pluralize(singular);
return `${formatInteger(n)} ${n === 1 ? singular : plural}`;
}
diff --git a/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.scss b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.scss
new file mode 100644
index 00000000000..430cdc300d1
--- /dev/null
+++ b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.scss
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import '../../../variables';
+
+.destination-pages-dialog {
+ &.#{$bp-ns}-dialog {
+ min-width: 700px;
+ min-height: 480px;
+ }
+}
diff --git a/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.tsx b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.tsx
new file mode 100644
index 00000000000..1e40aefdd08
--- /dev/null
+++ b/web-console/src/views/workbench-view/destination-pages-dialog/destination-pages-dialog.tsx
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Button, Classes, Dialog } from '@blueprintjs/core';
+import React from 'react';
+
+import type { Execution } from '../../../druid-models';
+import { DestinationPagesPane } from '../destination-pages-pane/destination-pages-pane';
+
+import './destination-pages-dialog.scss';
+
+export interface DestinationPagesDialogProps {
+ execution: Execution;
+ onClose(): void;
+}
+
+export const DestinationPagesDialog = React.memo(function DestinationPagesDialog(
+ props: DestinationPagesDialogProps,
+) {
+ const { execution, onClose } = props;
+
+ return (
+
+ );
+});
diff --git a/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.tsx b/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.tsx
new file mode 100644
index 00000000000..20f68a8af69
--- /dev/null
+++ b/web-console/src/views/workbench-view/destination-pages-pane/destination-pages-pane.tsx
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AnchorButton, Button } from '@blueprintjs/core';
+import { IconNames } from '@blueprintjs/icons';
+import React from 'react';
+import ReactTable from 'react-table';
+
+import type { Execution } from '../../../druid-models';
+import { Api, UrlBaser } from '../../../singletons';
+import {
+ clamp,
+ downloadUrl,
+ formatBytes,
+ formatInteger,
+ pluralIfNeeded,
+ wait,
+} from '../../../utils';
+
+const MAX_DETAIL_ROWS = 20;
+
+interface DestinationPagesPaneProps {
+ execution: Execution;
+}
+
+export const DestinationPagesPane = React.memo(function DestinationPagesPane(
+ props: DestinationPagesPaneProps,
+) {
+ const { execution } = props;
+ const destination = execution.destination;
+ const pages = execution.destinationPages;
+ if (!pages) return null;
+ const id = Api.encodePath(execution.id);
+
+ const numTotalRows = destination?.numTotalRows;
+
+ function getPageUrl(pageIndex: number) {
+ return UrlBaser.base(`/druid/v2/sql/statements/${id}/results?page=${pageIndex}`);
+ }
+
+ function getPageFilename(pageIndex: number) {
+ return `${id}_page${pageIndex}.jsonl`;
+ }
+
+ async function downloadAllPages() {
+ if (!pages) return;
+ for (let i = 0; i < pages.length; i++) {
+ downloadUrl(getPageUrl(i), getPageFilename(i));
+ await wait(100);
+ }
+ }
+
+ return (
+
+
+ {`${
+ typeof numTotalRows === 'number' ? pluralIfNeeded(numTotalRows, 'row') : 'Results'
+ } have been written to ${pluralIfNeeded(pages.length, 'page')}. `}
+ {pages.length > 1 && (
+
+
MAX_DETAIL_ROWS}
+ columns={[
+ {
+ Header: 'Page number',
+ id: 'id',
+ accessor: 'id',
+ className: 'padded',
+ width: 100,
+ },
+ {
+ Header: 'Number of rows',
+ id: 'numRows',
+ accessor: 'numRows',
+ className: 'padded',
+ width: 200,
+ Cell: ({ value }) => formatInteger(value),
+ },
+ {
+ Header: 'Size',
+ id: 'sizeInBytes',
+ accessor: 'sizeInBytes',
+ className: 'padded',
+ width: 200,
+ Cell: ({ value }) => formatBytes(value),
+ },
+ {
+ Header: '',
+ id: 'download',
+ accessor: 'id',
+ sortable: false,
+ width: 300,
+ Cell: ({ value }) => (
+
+ ),
+ },
+ ]}
+ />
+
+ );
+});
diff --git a/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap b/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap
index fb8c7a0eff5..6f3c23bee00 100644
--- a/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap
+++ b/web-console/src/views/workbench-view/execution-details-pane/__snapshots__/execution-details-pane.spec.tsx.snap
@@ -23,6 +23,7 @@ exports[`ExecutionDetailsPane matches snapshot no init tab 1`] = `
"label": "Native query",
},
undefined,
+ undefined,
Object {
"icon": "error",
"id": "error",
@@ -38,7 +39,10 @@ exports[`ExecutionDetailsPane matches snapshot no init tab 1`] = `
>
- General info for query-8f889312-e989-4b4c-9895-485a1fe796d3 ingesting into "kttm-blank-lines"
+ General info for query-af8a263d-213f-418e-ad8d-37d55beff59b ingesting into "kttm-blank-lines"
+
+
+ Results written to dataSource
{`General info for ${execution.id}${
ingestDatasource ? ` ingesting into ${T(ingestDatasource)}` : ''
}`}
+ {execution.destination && (
+
+ {`Results written to ${execution.destination.type}`}
+ {execution.destinationPages
+ ? ` (${pluralIfNeeded(execution.destinationPages.length, 'page')})`
+ : undefined}
+
+ )}
{execution.error && }
{execution.stages ? (
);
+ case 'pages':
+ if (!execution.destinationPages) return;
+ return ;
+
case 'error':
return ;
@@ -129,6 +151,11 @@ export const ExecutionDetailsPane = React.memo(function ExecutionDetailsPane(
label: 'Results',
icon: IconNames.TH,
},
+ execution.destinationPages && {
+ id: 'pages',
+ label: 'Result pages',
+ icon: IconNames.APPLICATIONS,
+ },
execution.error && {
id: 'error',
label: 'Error',
diff --git a/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap b/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap
index a57de9ed745..f6000ab38d4 100644
--- a/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap
+++ b/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap
@@ -21,7 +21,7 @@ exports[`ExecutionErrorPane matches snapshot 1`] = `
Failed task ID:
(on host:
diff --git a/web-console/src/views/workbench-view/execution-stages-pane/__snapshots__/execution-stages-pane.spec.tsx.snap b/web-console/src/views/workbench-view/execution-stages-pane/__snapshots__/execution-stages-pane.spec.tsx.snap
index f28821b1b35..a5018aec85c 100644
--- a/web-console/src/views/workbench-view/execution-stages-pane/__snapshots__/execution-stages-pane.spec.tsx.snap
+++ b/web-console/src/views/workbench-view/execution-stages-pane/__snapshots__/execution-stages-pane.spec.tsx.snap
@@ -158,7 +158,7 @@ exports[`ExecutionStagesPane matches snapshot 1`] = `
Array [
Object {
"definition": Object {
- "id": "8af42220-2724-4a76-b39f-c2f98df2de69_0",
+ "id": "ad318360-2ccf-4afc-b221-27c8704bf4fe_0",
"input": Array [
Object {
"inputFormat": Object {
@@ -196,15 +196,16 @@ exports[`ExecutionStagesPane matches snapshot 1`] = `
"context": Object {
"__timeColumn": "v0",
"__user": "allowAll",
+ "executionMode": "async",
"finalize": false,
"finalizeAggregations": false,
"groupByEnableMultiValueUnnesting": false,
"maxNumTasks": 2,
"maxParseExceptions": 0,
- "queryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "queryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"scanSignature": "[{\\"name\\":\\"agent_type\\",\\"type\\":\\"STRING\\"},{\\"name\\":\\"v0\\",\\"type\\":\\"LONG\\"}]",
"sqlInsertSegmentGranularity": "{\\"type\\":\\"all\\"}",
- "sqlQueryId": "5aa683e2-a6ee-4655-a834-a643e91055b1",
+ "sqlQueryId": "93a855fa-c35a-48df-b596-6bc98eed1101",
"sqlReplaceTimeChunks": "all",
},
"dataSource": Object {
@@ -283,17 +284,17 @@ exports[`ExecutionStagesPane matches snapshot 1`] = `
},
],
},
- "duration": 20483,
+ "duration": 21324,
"partitionCount": 1,
"phase": "FINISHED",
"sort": true,
"stageNumber": 0,
- "startTime": "2023-06-19T05:39:26.711Z",
+ "startTime": "2023-08-01T03:12:59.865Z",
"workerCount": 1,
},
Object {
"definition": Object {
- "id": "8af42220-2724-4a76-b39f-c2f98df2de69_1",
+ "id": "ad318360-2ccf-4afc-b221-27c8704bf4fe_1",
"input": Array [
Object {
"stage": 0,
@@ -359,11 +360,11 @@ exports[`ExecutionStagesPane matches snapshot 1`] = `
},
"signature": Array [],
},
- "duration": 2381,
+ "duration": 2070,
"partitionCount": 1,
"phase": "FINISHED",
"stageNumber": 1,
- "startTime": "2023-06-19T05:39:47.166Z",
+ "startTime": "2023-08-01T03:13:21.156Z",
"workerCount": 1,
},
]
diff --git a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
index 182c47ff56c..046de0ffb5f 100644
--- a/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
+++ b/web-console/src/views/workbench-view/execution-submit-dialog/execution-submit-dialog.tsx
@@ -23,6 +23,7 @@ import AceEditor from 'react-ace';
import { Execution } from '../../../druid-models';
import { AppToaster } from '../../../singletons';
+import type { QueryDetailArchive } from '../../../utils';
import { offsetToRowColumn } from '../../../utils';
import './execution-submit-dialog.scss';
@@ -39,7 +40,7 @@ export const ExecutionSubmitDialog = React.memo(function ExecutionSubmitDialog(
const [archive, setArchive] = useState('');
function handleSubmit(): void {
- let parsed: any;
+ let parsed: QueryDetailArchive;
try {
parsed = JSONBig.parse(archive);
} catch (e) {
@@ -55,13 +56,13 @@ export const ExecutionSubmitDialog = React.memo(function ExecutionSubmitDialog(
}
let execution: Execution | undefined;
- const detailArchiveVersion = parsed.detailArchiveVersion ?? parsed.profileVersion;
+ const detailArchiveVersion = parsed.detailArchiveVersion ?? (parsed as any).profileVersion;
if (typeof detailArchiveVersion === 'number') {
try {
if (detailArchiveVersion === 2) {
- execution = Execution.fromTaskReport(parsed.reports).updateWithTaskPayload(
- parsed.payload,
- );
+ execution = Execution.fromTaskReport(parsed.reports)
+ .updateWithTaskPayload(parsed.payload)
+ .updateWithAsyncStatus(parsed.statementsStatus);
} else {
AppToaster.show({
intent: Intent.DANGER,
@@ -76,9 +77,9 @@ export const ExecutionSubmitDialog = React.memo(function ExecutionSubmitDialog(
});
return;
}
- } else if (typeof parsed.multiStageQuery === 'object') {
+ } else if (typeof (parsed as any).multiStageQuery === 'object') {
try {
- execution = Execution.fromTaskReport(parsed);
+ execution = Execution.fromTaskReport(parsed as any);
} catch (e) {
AppToaster.show({
intent: Intent.DANGER,
diff --git a/web-console/src/views/workbench-view/execution-summary-panel/execution-summary-panel.tsx b/web-console/src/views/workbench-view/execution-summary-panel/execution-summary-panel.tsx
index c98c94c4651..bdeb738196d 100644
--- a/web-console/src/views/workbench-view/execution-summary-panel/execution-summary-panel.tsx
+++ b/web-console/src/views/workbench-view/execution-summary-panel/execution-summary-panel.tsx
@@ -20,10 +20,11 @@ import { Button, ButtonGroup, Menu, MenuDivider, MenuItem, Position } from '@blu
import { IconNames } from '@blueprintjs/icons';
import { Popover2 } from '@blueprintjs/popover2';
import type { JSX } from 'react';
-import React from 'react';
+import React, { useState } from 'react';
import type { Execution } from '../../../druid-models';
import { downloadQueryResults, formatDurationHybrid, pluralIfNeeded } from '../../../utils';
+import { DestinationPagesDialog } from '../destination-pages-dialog/destination-pages-dialog';
import './execution-summary-panel.scss';
@@ -37,6 +38,7 @@ export const ExecutionSummaryPanel = React.memo(function ExecutionSummaryPanel(
props: ExecutionSummaryPanelProps,
) {
const { execution, onExecutionDetail, onReset } = props;
+ const [showDestinationPages, setShowDestinationPages] = useState(false);
const queryResult = execution?.result;
const buttons: JSX.Element[] = [];
@@ -71,21 +73,30 @@ export const ExecutionSummaryPanel = React.memo(function ExecutionSummaryPanel(
}
}}
/>,
-
-
- ,
+ execution?.destination?.type === 'durableStorage' && execution.destinationPages ? (
+