0
# Result Handling and Display
1
2
Type-safe result containers with support for materialized and streaming results, plus multiple display formats. The result handling system provides comprehensive support for both batch and streaming query results with efficient pagination and real-time change streaming.
3
4
## Capabilities
5
6
### ResultDescriptor Class
7
8
Metadata container for query results providing comprehensive result information and access patterns.
9
10
```java { .api }
11
public class ResultDescriptor {
12
/**
13
* Get unique result identifier for tracking and access
14
* @return String identifier for this result set
15
*/
16
public String getResultId();
17
18
/**
19
* Get table schema information for result structure
20
* @return ResolvedSchema with column names, types, and metadata
21
*/
22
public ResolvedSchema getResultSchema();
23
24
/**
25
* Check if result is materialized in memory for pagination
26
* @return true if result supports random page access
27
*/
28
public boolean isMaterialized();
29
30
/**
31
* Check if result should use tableau display format
32
* @return true for direct tableau output, false for interactive display
33
*/
34
public boolean isTableauMode();
35
36
/**
37
* Check if result comes from streaming query execution
38
* @return true for streaming queries, false for batch queries
39
*/
40
public boolean isStreamingMode();
41
42
/**
43
* Get maximum column width for display formatting
44
* @return Maximum character width for column display
45
*/
46
public int maxColumnWidth();
47
}
48
```
49
50
**Usage Example:**
51
52
```java
53
// Execute query and get result descriptor
54
QueryOperation query = (QueryOperation) executor.parseOperation(sessionId, "SELECT * FROM orders");
55
ResultDescriptor descriptor = executor.executeQuery(sessionId, query);
56
57
// Check result characteristics
58
System.out.println("Result ID: " + descriptor.getResultId());
59
System.out.println("Is materialized: " + descriptor.isMaterialized());
60
System.out.println("Is streaming: " + descriptor.isStreamingMode());
61
System.out.println("Use tableau mode: " + descriptor.isTableauMode());
62
63
// Access schema information
64
ResolvedSchema schema = descriptor.getResultSchema();
65
schema.getColumns().forEach(column ->
66
System.out.println("Column: " + column.getName() + " Type: " + column.getDataType())
67
);
68
```
69
70
### TypedResult Class
71
72
Generic result container with type information providing type-safe access to result data and metadata.
73
74
```java { .api }
75
public class TypedResult<P> {
76
/**
77
* Get result type indicating data availability
78
* @return ResultType enum value
79
*/
80
public ResultType getType();
81
82
/**
83
* Get actual result payload data
84
* @return Payload data of type P, or null for non-PAYLOAD results
85
*/
86
public P getPayload();
87
88
/**
89
* Set result type
90
* @param type ResultType to set
91
*/
92
public void setType(ResultType type);
93
94
/**
95
* Set result payload
96
* @param payload Payload data to set
97
*/
98
public void setPayload(P payload);
99
}
100
```
101
102
### TypedResult Factory Methods
103
104
Static factory methods for creating typed results with appropriate type indicators.
105
106
```java { .api }
107
/**
108
* Create empty result indicating no data available
109
* @return TypedResult with EMPTY type
110
*/
111
public static <T> TypedResult<T> empty();
112
113
/**
114
* Create result with actual data payload
115
* @param payload Data to include in result
116
* @return TypedResult with PAYLOAD type and data
117
*/
118
public static <T> TypedResult<T> payload(T payload);
119
120
/**
121
* Create end-of-stream marker result
122
* @return TypedResult with EOS type indicating stream completion
123
*/
124
public static <T> TypedResult<T> endOfStream();
125
```
126
127
**Usage Example:**
128
129
```java
130
// Handle different result types
131
TypedResult<List<Row>> result = executor.retrieveResultChanges(sessionId, resultId);
132
133
switch (result.getType()) {
134
case PAYLOAD:
135
List<Row> rows = result.getPayload();
136
System.out.println("Received " + rows.size() + " rows");
137
rows.forEach(this::processRow);
138
break;
139
140
case EMPTY:
141
System.out.println("No new data available");
142
// Continue polling or wait
143
break;
144
145
case EOS:
146
System.out.println("Stream has ended");
147
// Cleanup and exit polling loop
148
break;
149
}
150
```
151
152
### ResultType Enumeration
153
154
Enumeration defining the type of result data availability.
155
156
```java { .api }
157
public enum ResultType {
158
/** Result contains actual data payload */
159
PAYLOAD,
160
161
/** Result is empty - no data currently available */
162
EMPTY,
163
164
/** End of stream - no more data will be available */
165
EOS
166
}
167
```
168
169
## Result Interface Hierarchy
170
171
### DynamicResult Interface
172
173
Base interface for dynamic result handling providing common result operations.
174
175
```java { .api }
176
public interface DynamicResult extends AutoCloseable {
177
/**
178
* Check if result is materialized in memory
179
* @return true if result supports random access, false for streaming-only
180
*/
181
boolean isMaterialized();
182
183
/**
184
* Close result and release associated resources
185
* @throws IOException if cleanup fails
186
*/
187
void close() throws IOException;
188
}
189
```
190
191
### MaterializedResult Interface
192
193
Interface for materialized results supporting pagination and random access.
194
195
```java { .api }
196
public interface MaterializedResult extends DynamicResult {
197
/**
198
* Create materialized snapshot with specified page size
199
* @param pageSize Number of rows per page
200
* @return TypedResult containing total page count
201
*/
202
TypedResult<Integer> snapshot(int pageSize);
203
204
/**
205
* Retrieve specific page of results
206
* @param page Page number (0-based indexing)
207
* @return List of rows for the requested page
208
*/
209
List<Row> retrievePage(int page);
210
}
211
```
212
213
**Usage Example:**
214
215
```java
216
// Handle materialized results with pagination
217
if (result instanceof MaterializedResult) {
218
MaterializedResult materializedResult = (MaterializedResult) result;
219
220
// Create snapshot with 100 rows per page
221
TypedResult<Integer> pageCountResult = materializedResult.snapshot(100);
222
if (pageCountResult.getType() == ResultType.PAYLOAD) {
223
int totalPages = pageCountResult.getPayload();
224
System.out.println("Total pages: " + totalPages);
225
226
// Retrieve each page
227
for (int page = 0; page < totalPages; page++) {
228
List<Row> pageRows = materializedResult.retrievePage(page);
229
System.out.println("Page " + page + ": " + pageRows.size() + " rows");
230
pageRows.forEach(this::processRow);
231
}
232
}
233
}
234
```
235
236
### ChangelogResult Interface
237
238
Interface for streaming results providing incremental change access.
239
240
```java { .api }
241
public interface ChangelogResult extends DynamicResult {
242
/**
243
* Retrieve incremental changes from streaming result
244
* @return TypedResult containing list of changed rows or status
245
*/
246
TypedResult<List<Row>> retrieveChanges();
247
}
248
```
249
250
**Usage Example:**
251
252
```java
253
// Handle streaming results with changelog
254
if (result instanceof ChangelogResult) {
255
ChangelogResult changelogResult = (ChangelogResult) result;
256
257
// Poll for changes
258
while (true) {
259
TypedResult<List<Row>> changes = changelogResult.retrieveChanges();
260
261
switch (changes.getType()) {
262
case PAYLOAD:
263
List<Row> changedRows = changes.getPayload();
264
changedRows.forEach(row -> {
265
// Process row changes - each row includes change type (+I, -D, -U, +U)
266
RowKind kind = row.getKind();
267
System.out.println("Change type: " + kind + ", Data: " + row);
268
});
269
break;
270
271
case EMPTY:
272
Thread.sleep(100); // Wait before next poll
273
break;
274
275
case EOS:
276
System.out.println("Stream completed");
277
return; // Exit polling loop
278
}
279
}
280
}
281
```
282
283
## Result Display Components
284
285
### CliTableauResultView Class
286
287
Tableau-style result display providing direct formatted output without interactive features.
288
289
```java { .api }
290
public class CliTableauResultView implements AutoCloseable {
291
/**
292
* Create tableau result view
293
* @param terminal Terminal for output
294
* @param executor Executor for result access
295
* @param sessionId Session identifier
296
* @param resultDesc Result descriptor for metadata
297
*/
298
public CliTableauResultView(Terminal terminal, Executor executor, String sessionId, ResultDescriptor resultDesc);
299
300
/**
301
* Display results in tableau format
302
* Outputs formatted table directly to terminal
303
*/
304
public void displayResults();
305
306
/**
307
* Close view and cleanup resources
308
*/
309
public void close();
310
}
311
```
312
313
**Usage Example:**
314
315
```java
316
// Display results in tableau format
317
try (CliTableauResultView tableauView = new CliTableauResultView(
318
terminal, executor, sessionId, resultDescriptor)) {
319
tableauView.displayResults();
320
}
321
```
322
323
### CliView Abstract Class
324
325
Base class for CLI view components providing common view functionality.
326
327
```java { .api }
328
public abstract class CliView<OP, OUT> {
329
/**
330
* Get associated CLI client
331
* @return CliClient instance
332
*/
333
protected CliClient getClient();
334
335
/**
336
* Get terminal for output operations
337
* @return Terminal instance
338
*/
339
protected Terminal getTerminal();
340
341
/**
342
* Check if terminal is plain (limited features)
343
* @return true if terminal has limited capabilities
344
*/
345
protected boolean isPlainTerminal();
346
}
347
```
348
349
### CliResultView Abstract Class
350
351
Base class for result display views providing common result handling.
352
353
```java { .api }
354
public abstract class CliResultView<OP> extends CliView<OP, Void> {
355
/**
356
* Open result view for interaction
357
*/
358
public abstract void open();
359
360
/**
361
* Get result descriptor
362
* @return ResultDescriptor for this view
363
*/
364
protected ResultDescriptor getResultDescriptor();
365
}
366
```
367
368
## Row Processing and Data Types
369
370
### Row Access Patterns
371
372
Working with Row objects in results:
373
374
```java
375
// Process row data
376
void processRow(Row row) {
377
// Get row kind for change tracking
378
RowKind kind = row.getKind();
379
380
// Access fields by position
381
Object field0 = row.getField(0);
382
Object field1 = row.getField(1);
383
384
// Access fields with type safety
385
String name = row.getFieldAs(0, String.class);
386
Integer age = row.getFieldAs(1, Integer.class);
387
388
// Iterate over all fields
389
for (int i = 0; i < row.getArity(); i++) {
390
Object field = row.getField(i);
391
System.out.println("Field " + i + ": " + field);
392
}
393
}
394
```
395
396
### Schema Integration
397
398
Using ResolvedSchema for type-safe result processing:
399
400
```java
401
void processResultWithSchema(ResultDescriptor descriptor, List<Row> rows) {
402
ResolvedSchema schema = descriptor.getResultSchema();
403
List<Column> columns = schema.getColumns();
404
405
for (Row row : rows) {
406
for (int i = 0; i < columns.size(); i++) {
407
Column column = columns.get(i);
408
Object value = row.getField(i);
409
410
System.out.printf("Column %s (%s): %s%n",
411
column.getName(),
412
column.getDataType(),
413
value);
414
}
415
}
416
}
417
```
418
419
## Error Handling
420
421
Result handling includes comprehensive error management:
422
423
```java
424
try {
425
TypedResult<List<Row>> result = executor.retrieveResultChanges(sessionId, resultId);
426
// Process result
427
} catch (SqlExecutionException e) {
428
if (e.getMessage().contains("Result expired")) {
429
System.err.println("Result has expired - restart query");
430
} else if (e.getMessage().contains("Result not found")) {
431
System.err.println("Invalid result ID");
432
} else {
433
System.err.println("Execution error: " + e.getMessage());
434
}
435
}
436
437
// Handle pagination errors
438
try {
439
List<Row> page = materializedResult.retrievePage(pageNumber);
440
} catch (IndexOutOfBoundsException e) {
441
System.err.println("Invalid page number: " + pageNumber);
442
} catch (IllegalStateException e) {
443
System.err.println("Result snapshot has expired");
444
}
445
```
446
447
## Performance Considerations
448
449
### Efficient Result Processing
450
451
```java
452
// Batch process rows for better performance
453
List<Row> batch = new ArrayList<>();
454
TypedResult<List<Row>> result = executor.retrieveResultChanges(sessionId, resultId);
455
456
if (result.getType() == ResultType.PAYLOAD) {
457
batch.addAll(result.getPayload());
458
459
// Process in batches of 1000 rows
460
if (batch.size() >= 1000) {
461
processBatch(batch);
462
batch.clear();
463
}
464
}
465
```
466
467
### Memory Management
468
469
```java
470
// Use try-with-resources for automatic cleanup
471
try (CliTableauResultView view = new CliTableauResultView(terminal, executor, sessionId, descriptor)) {
472
view.displayResults();
473
} // Automatic resource cleanup
474
475
// Cancel long-running queries when needed
476
if (shouldCancel) {
477
executor.cancelQuery(sessionId, resultId);
478
}
479
```
480
481
The result handling and display system provides a comprehensive framework for managing both batch and streaming query results with efficient memory usage, type safety, and flexible display options.