@@ -315,6 +315,200 @@ int mysql_helper_stmt(struct mysql_helper *mysql_helper,
315315 return 0 ;
316316}
317317
318+ int mysql_helper_vstmt (struct mysql_helper * mysql_helper ,
319+ const char * query ,
320+ size_t query_len ,
321+ const char * params ,
322+ const char * fields ,
323+ void * * input )
324+ {
325+ /*
326+ * 0. Cleanup from previous call
327+ */
328+ if (mysql_helper -> stmt ) {
329+ mysql_stmt_close (mysql_helper -> stmt );
330+ mysql_helper -> stmt = NULL ;
331+ vmbuf_reset (& mysql_helper -> buf );
332+ }
333+ /*
334+ * 1. Prepare statement
335+ */
336+ mysql_helper -> stmt = mysql_stmt_init (& mysql_helper -> mysql );
337+ if (!mysql_helper -> stmt )
338+ return report_error (mysql_helper );
339+
340+ if (0 != mysql_stmt_prepare (mysql_helper -> stmt , query , query_len ))
341+ return report_stmt_error (mysql_helper );
342+ /*
343+ * 2. Bind parameters if there are any
344+ */
345+ uint32_t nparams = strlen (params );
346+ uint32_t n = mysql_stmt_param_count (mysql_helper -> stmt );
347+ if (nparams != n ) {
348+ LOGGER_ERROR ("num params != num params in query (%u != %u)" , nparams , n );
349+ return -1 ;
350+ }
351+ const char * p ;
352+ uint32_t i ;
353+
354+ /* TODO: move to internal vmbuf (mysql_helper), so
355+ mysql_stmt_execute can be called multiple times when inserting
356+ data */
357+ unsigned long plengths [nparams ];
358+ int ptypes [nparams ];
359+ my_bool pnulls [nparams ];
360+ MYSQL_BIND pbind [nparams ];
361+
362+ if (nparams > 0 ) {
363+ memset (pbind , 0 , sizeof (pbind ));
364+ MYSQL_BIND * pbind_ptr = pbind ;
365+ for (i = 0 , p = params ; * p ; ++ p , ++ pbind_ptr , ++ i ) {
366+ char c = * p ;
367+ char * str ;
368+ switch (tolower (c )) {
369+ case 'd' :
370+ ptypes [i ] = MYSQL_TYPE_LONG ;
371+ pbind_ptr -> buffer = (int * )(* input );
372+ pnulls [i ] = (pbind_ptr -> buffer == NULL );
373+ pbind_ptr -> is_unsigned = isupper (c ) ? 1 : 0 ;
374+ ++ input ;
375+ break ;
376+ case 'f' :
377+ ptypes [i ] = MYSQL_TYPE_DOUBLE ;
378+ pbind_ptr -> buffer = (double * )(* input );
379+ pnulls [i ] = (pbind_ptr -> buffer == NULL );
380+ ++ input ;
381+ break ;
382+ case 's' :
383+ ptypes [i ] = MYSQL_TYPE_STRING ;
384+ if (isupper (c )) {
385+ plengths [i ] = * (size_t * )input ;
386+ str = (char * )(* input );
387+ ++ input ;
388+ } else {
389+ str = (char * )(* input );
390+ plengths [i ] = strlen (str );
391+ }
392+ pnulls [i ] = (str == NULL );
393+ pbind_ptr -> buffer = str ;
394+ pbind_ptr -> buffer_length = plengths [i ];
395+ pbind_ptr -> length = & plengths [i ];
396+ ++ input ;
397+ break ;
398+ }
399+ pbind_ptr -> buffer_type = ptypes [i ];
400+ pbind_ptr -> is_null = & pnulls [i ];
401+ }
402+
403+ if (0 != mysql_stmt_bind_param (mysql_helper -> stmt , pbind ))
404+ return report_stmt_error (mysql_helper );
405+ }
406+ /*
407+ * 3. Prepare result field bindings
408+ */
409+ uint32_t nfields = strlen (fields );
410+ MYSQL_BIND bind [nfields ];
411+ unsigned long qlength [nfields ];
412+ int ftypes [nfields ];
413+ size_t str_ofs [nfields ];
414+
415+ if (nfields > 0 ) {
416+ MYSQL_RES * rs = mysql_stmt_result_metadata (mysql_helper -> stmt );
417+ if (!rs )
418+ return report_stmt_error (mysql_helper );
419+ n = mysql_num_fields (rs );
420+ if (n != nfields ) {
421+ LOGGER_ERROR ("num args != num fields in query (%u != %u)" , nfields , n );
422+ mysql_free_result (rs );
423+ return -1 ;
424+ }
425+ mysql_helper -> num_fields = n ;
426+ MYSQL_FIELD * qfields = mysql_fetch_fields (rs );
427+ for (i = 0 , p = fields ; * p ; ++ p , ++ i ) {
428+ ftypes [i ] = qfields [i ].type ;
429+ char c = * p ;
430+ c = tolower (c );
431+ switch (c ) {
432+ case 'd' :
433+ ftypes [i ] = MYSQL_TYPE_LONG ;
434+ break ;
435+ case 'f' :
436+ ftypes [i ] = MYSQL_TYPE_DOUBLE ;
437+ break ;
438+ case 's' :
439+ ftypes [i ] = MYSQL_TYPE_STRING ;
440+ break ;
441+ }
442+ qlength [i ] = ribs_mysql_get_storage_size (ftypes [i ], qfields [i ].length );
443+ }
444+ mysql_free_result (rs );
445+ size_t data_ofs = vmbuf_alloc_aligned (& mysql_helper -> buf , sizeof (char * * ) * nfields );
446+ size_t length_ofs = vmbuf_alloc_aligned (& mysql_helper -> buf , sizeof (unsigned long ) * nfields );
447+ size_t error_ofs = vmbuf_alloc_aligned (& mysql_helper -> buf , sizeof (my_bool ) * nfields );
448+ size_t is_null_ofs = vmbuf_alloc_aligned (& mysql_helper -> buf , sizeof (my_bool ) * nfields );
449+ size_t is_str_ofs = vmbuf_alloc_aligned (& mysql_helper -> buf , sizeof (mysql_helper -> is_str [0 ]) * nfields );
450+ /* allocate space for the strings */
451+ for (i = 0 , p = fields ; * p ; ++ p , ++ i ) {
452+ switch (tolower (* p )) {
453+ case 's' :
454+ str_ofs [i ] = vmbuf_alloc_aligned (& mysql_helper -> buf , qlength [i ] + 1 );
455+ break ;
456+ }
457+ }
458+ mysql_helper -> data = (char * * )vmbuf_data_ofs (& mysql_helper -> buf , data_ofs );
459+ mysql_helper -> length = (unsigned long * )vmbuf_data_ofs (& mysql_helper -> buf , length_ofs );
460+ mysql_helper -> is_error = (my_bool * )vmbuf_data_ofs (& mysql_helper -> buf , error_ofs );
461+ mysql_helper -> is_null = (my_bool * )vmbuf_data_ofs (& mysql_helper -> buf , is_null_ofs );
462+ mysql_helper -> is_str = (int8_t * )vmbuf_data_ofs (& mysql_helper -> buf , is_str_ofs );
463+ memset (mysql_helper -> is_str , 0 , sizeof (mysql_helper -> is_str [0 ]) * nfields );
464+ memset (bind , 0 , sizeof (MYSQL_BIND ) * nfields );
465+ MYSQL_BIND * bind_ptr = bind ;
466+ for (i = 0 , p = fields ; * p ; ++ p , ++ bind_ptr , ++ i ) {
467+ char c = * p ;
468+ bind_ptr -> is_unsigned = isupper (c ) ? 1 : 0 ;
469+ bind_ptr -> is_null = & mysql_helper -> is_null [i ];
470+ bind_ptr -> error = & mysql_helper -> is_error [i ];
471+ bind_ptr -> length = & mysql_helper -> length [i ];
472+ bind_ptr -> buffer_type = ftypes [i ];
473+ c = tolower (c );
474+ char * * str ;
475+ switch (c ) {
476+ case 'd' :
477+ bind_ptr -> buffer = (int * )(* input );
478+ bind_ptr -> buffer_length = sizeof (int );
479+ ++ input ;
480+ break ;
481+ case 'f' :
482+ bind_ptr -> buffer = (double * )(* input );
483+ bind_ptr -> buffer_length = sizeof (double );
484+ ++ input ;
485+ break ;
486+ case 's' :
487+ str = (char * * )(* input );
488+ * str = vmbuf_data_ofs (& mysql_helper -> buf , str_ofs [i ]);
489+ bind_ptr -> buffer = * str ;
490+ bind_ptr -> buffer_length = qlength [i ];
491+ mysql_helper -> is_str [i ] = 1 ;
492+ ++ input ;
493+ break ;
494+ }
495+ mysql_helper -> data [i ] = bind_ptr -> buffer ;
496+ }
497+ }
498+ /*
499+ * 4. Execute the query
500+ */
501+ if (0 != mysql_stmt_execute (mysql_helper -> stmt ))
502+ return report_stmt_error (mysql_helper );
503+ /*
504+ * 5. Bind result fields
505+ */
506+ if (nfields > 0 && 0 != mysql_stmt_bind_result (mysql_helper -> stmt , bind ))
507+ return report_stmt_error (mysql_helper );
508+
509+ return 0 ;
510+ }
511+
318512static int _mysql_helper_init_bind_map (void * data , size_t n , struct mysql_helper_column_map * map , MYSQL_BIND * pbind , unsigned long * plengths , my_bool * pnulls , struct vmbuf * tb ) {
319513 if (n == 0 ) return 0 ;
320514 memset (pbind , 0 , sizeof (MYSQL_BIND ) * n );
0 commit comments