@@ -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 ;
67use indexmap:: IndexMap ;
78use 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