Skip to content

Commit c19fec4

Browse files
committed
fix(cubeorchestrator): Increase VerifierOptions max_tables to 10M
And add parser tests
1 parent cabed15 commit c19fec4

File tree

1 file changed

+215
-3
lines changed

1 file changed

+215
-3
lines changed

rust/cubeorchestrator/src/query_message_parser.rs

Lines changed: 215 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use crate::{
22
query_result_transform::{DBResponsePrimitive, DBResponseValue},
33
transport::JsRawData,
44
};
5-
use cubeshared::codegen::{root_as_http_message, HttpCommand};
5+
use cubeshared::codegen::{root_as_http_message_with_opts, HttpCommand};
6+
use flatbuffers::VerifierOptions;
67
use indexmap::IndexMap;
78
use neon::prelude::Finalize;
89

@@ -48,8 +49,11 @@ impl QueryResult {
4849
columns_pos: IndexMap::new(),
4950
};
5051

51-
let http_message =
52-
root_as_http_message(msg_data).map_err(|_| ParseError::FlatBufferError)?;
52+
let mut opts = VerifierOptions::default();
53+
opts.max_tables = 10_000_000; // Support up to 10M tables
54+
55+
let http_message = root_as_http_message_with_opts(&opts, msg_data)
56+
.map_err(|_| ParseError::FlatBufferError)?;
5357

5458
match http_message.command_type() {
5559
HttpCommand::HttpError => {
@@ -145,3 +149,211 @@ impl QueryResult {
145149
})
146150
}
147151
}
152+
153+
#[cfg(test)]
154+
mod tests {
155+
use super::*;
156+
use cubeshared::codegen::{
157+
root_as_http_message_unchecked, HttpColumnValue, HttpColumnValueArgs, HttpCommand,
158+
HttpMessage, HttpMessageArgs, HttpResultSet, HttpResultSetArgs, HttpRow, HttpRowArgs,
159+
};
160+
use flatbuffers::FlatBufferBuilder;
161+
162+
/// Helper function to create a test HttpMessage with a given number of rows and columns
163+
fn create_test_message(num_rows: usize, num_columns: usize) -> Vec<u8> {
164+
let mut builder = FlatBufferBuilder::new();
165+
166+
// Create column names
167+
let column_names: Vec<_> = (0..num_columns)
168+
.map(|i| builder.create_string(&format!("column_{}", i)))
169+
.collect();
170+
171+
// Create rows with values
172+
let mut rows_vec = Vec::with_capacity(num_rows);
173+
for row_idx in 0..num_rows {
174+
// Create column values for this row
175+
let mut values_vec = Vec::with_capacity(num_columns);
176+
for col_idx in 0..num_columns {
177+
let value_str = builder.create_string(&format!("row_{}_col_{}", row_idx, col_idx));
178+
let col_value = HttpColumnValue::create(
179+
&mut builder,
180+
&HttpColumnValueArgs {
181+
string_value: Some(value_str),
182+
},
183+
);
184+
values_vec.push(col_value);
185+
}
186+
187+
let values_vector = builder.create_vector(&values_vec);
188+
let row = HttpRow::create(
189+
&mut builder,
190+
&HttpRowArgs {
191+
values: Some(values_vector),
192+
},
193+
);
194+
rows_vec.push(row);
195+
}
196+
197+
// Create the result set
198+
let columns_vector = builder.create_vector(&column_names);
199+
let rows_vector = builder.create_vector(&rows_vec);
200+
201+
let result_set = HttpResultSet::create(
202+
&mut builder,
203+
&HttpResultSetArgs {
204+
columns: Some(columns_vector),
205+
rows: Some(rows_vector),
206+
},
207+
);
208+
209+
// Create the message
210+
let connection_id = builder.create_string("test_connection");
211+
let message = HttpMessage::create(
212+
&mut builder,
213+
&HttpMessageArgs {
214+
message_id: 1,
215+
command_type: HttpCommand::HttpResultSet,
216+
command: Some(result_set.as_union_value()),
217+
connection_id: Some(connection_id),
218+
},
219+
);
220+
221+
builder.finish(message, None);
222+
builder.finished_data().to_vec()
223+
}
224+
225+
#[test]
226+
fn test_parse_small_result_set() {
227+
// Small result set should work fine
228+
let msg_data = create_test_message(10, 5);
229+
let result = QueryResult::from_cubestore_fb(&msg_data);
230+
assert!(result.is_ok());
231+
232+
let query_result = result.unwrap();
233+
assert_eq!(query_result.columns.len(), 5);
234+
assert_eq!(query_result.rows.len(), 10);
235+
}
236+
237+
#[test]
238+
fn test_parse_medium_result_set() {
239+
// Medium result set: 1000 rows, 20 columns
240+
let msg_data = create_test_message(1000, 20);
241+
let result = QueryResult::from_cubestore_fb(&msg_data);
242+
assert!(result.is_ok());
243+
244+
let query_result = result.unwrap();
245+
assert_eq!(query_result.columns.len(), 20);
246+
assert_eq!(query_result.rows.len(), 1000);
247+
}
248+
249+
#[test]
250+
fn test_parse_large_result_set() {
251+
// Large result set: 10,000 rows, 30 columns
252+
// This should start showing verification issues
253+
let msg_data = create_test_message(10_000, 30);
254+
let result = QueryResult::from_cubestore_fb(&msg_data);
255+
assert!(result.is_ok());
256+
257+
let query_result = result.unwrap();
258+
assert_eq!(query_result.columns.len(), 30);
259+
assert_eq!(query_result.rows.len(), 10_000);
260+
}
261+
262+
#[test]
263+
fn test_parse_very_large_result_set() {
264+
// Very large result set: 33,000 rows, 40 columns
265+
let msg_data = create_test_message(33_000, 40);
266+
let result = QueryResult::from_cubestore_fb(&msg_data);
267+
assert!(result.is_ok());
268+
269+
let query_result = result.unwrap();
270+
assert_eq!(query_result.columns.len(), 40);
271+
assert_eq!(query_result.rows.len(), 33_000);
272+
}
273+
274+
#[test]
275+
fn test_parse_huge_result_set() {
276+
// Huge result set: 50,000 rows, 100 columns
277+
let msg_data = create_test_message(50_000, 100);
278+
let result = QueryResult::from_cubestore_fb(&msg_data);
279+
assert!(result.is_ok());
280+
281+
let query_result = result.unwrap();
282+
assert_eq!(query_result.columns.len(), 100);
283+
assert_eq!(query_result.rows.len(), 50_000);
284+
}
285+
286+
#[test]
287+
fn test_compare_with_unchecked_parse() {
288+
// Test to demonstrate that unchecked parsing would work
289+
let msg_data = create_test_message(33_000, 40);
290+
291+
// Checked version (current implementation)
292+
let checked_result = QueryResult::from_cubestore_fb(&msg_data);
293+
294+
// Try unchecked version to verify the data itself is valid
295+
let unchecked_result = unsafe {
296+
let http_message = root_as_http_message_unchecked(&msg_data);
297+
match http_message.command_type() {
298+
HttpCommand::HttpResultSet => {
299+
let result_set = http_message.command_as_http_result_set();
300+
if let Some(rs) = result_set {
301+
if let Some(rows) = rs.rows() {
302+
println!("Unchecked parse found {} rows", rows.len());
303+
Ok(rows.len())
304+
} else {
305+
Err("No rows")
306+
}
307+
} else {
308+
Err("No result set")
309+
}
310+
}
311+
_ => Err("Wrong command type"),
312+
}
313+
};
314+
315+
assert!(checked_result.is_ok());
316+
assert!(unchecked_result.is_ok());
317+
}
318+
319+
#[test]
320+
fn test_parse_with_custom_verifier_options() {
321+
use cubeshared::codegen::root_as_http_message_with_opts;
322+
use flatbuffers::VerifierOptions;
323+
324+
// Test that custom verifier options can handle large datasets
325+
let msg_data = create_test_message(33_000, 40);
326+
327+
// Create custom verifier options with increased limits
328+
let mut opts = VerifierOptions::default();
329+
opts.max_tables = 10_000_000; // Support up to 10M tables
330+
opts.max_apparent_size = 1 << 31; // 2GB limit
331+
332+
// This should succeed with custom options
333+
let result = root_as_http_message_with_opts(&opts, &msg_data);
334+
335+
match result {
336+
Ok(http_message) => {
337+
println!("Successfully parsed 33k rows with custom verifier options");
338+
match http_message.command_type() {
339+
HttpCommand::HttpResultSet => {
340+
let result_set = http_message.command_as_http_result_set();
341+
if let Some(rs) = result_set {
342+
if let Some(rows) = rs.rows() {
343+
assert_eq!(rows.len(), 33_000);
344+
println!(
345+
"Verified: {} rows with custom verifier options",
346+
rows.len()
347+
);
348+
}
349+
}
350+
}
351+
_ => panic!("Wrong command type"),
352+
}
353+
}
354+
Err(e) => {
355+
panic!("Failed to parse with custom verifier options: {:?}", e);
356+
}
357+
}
358+
}
359+
}

0 commit comments

Comments
 (0)