@@ -411,125 +411,129 @@ bind_parameter_count(VALUE self)
411411 return INT2NUM (sqlite3_bind_parameter_count (ctx -> st ));
412412}
413413
414- /* call-seq: stmt.fullscan_steps
415- *
416- * Return the number of times that SQLite has stepped forward in a table as part of a full table scan
417- */
418- static VALUE
419- fullscan_steps (VALUE self )
420- {
421- sqlite3StmtRubyPtr ctx ;
422- TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
423- REQUIRE_OPEN_STMT (ctx );
414+ enum stmt_stat_sym {
415+ stmt_stat_sym_fullscan_steps ,
416+ stmt_stat_sym_sorts ,
417+ stmt_stat_sym_autoindexes ,
418+ stmt_stat_sym_vm_steps ,
419+ #ifdef SQLITE_STMTSTATUS_REPREPARE
420+ stmt_stat_sym_reprepares ,
421+ #endif
422+ #ifdef SQLITE_STMTSTATUS_RUN
423+ stmt_stat_sym_runs ,
424+ #endif
425+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
426+ stmt_stat_sym_filter_misses ,
427+ #endif
428+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
429+ stmt_stat_sym_filter_hits ,
430+ #endif
431+ stmt_stat_sym_last
432+ };
424433
425- return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_FULLSCAN_STEP , 0 ));
426- }
434+ static VALUE stmt_stat_symbols [stmt_stat_sym_last ];
427435
428- /* call-seq: stmt.sorts
429- *
430- * Return the number of sort operations that have occurred
431- */
432- static VALUE
433- sorts (VALUE self )
436+ static void
437+ setup_stmt_stat_symbols (void )
434438{
435- sqlite3StmtRubyPtr ctx ;
436- TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
437- REQUIRE_OPEN_STMT (ctx );
438-
439- return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_SORT , 0 ));
439+ if (stmt_stat_symbols [0 ] == 0 ) {
440+ #define S (s ) stmt_stat_symbols[stmt_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
441+ S (fullscan_steps );
442+ S (sorts );
443+ S (autoindexes );
444+ S (vm_steps );
445+ #ifdef SQLITE_STMTSTATUS_REPREPARE
446+ S (reprepares );
447+ #endif
448+ #ifdef SQLITE_STMTSTATUS_RUN
449+ S (runs );
450+ #endif
451+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
452+ S (filter_misses );
453+ #endif
454+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
455+ S (filter_hits );
456+ #endif
457+ #undef S
458+ }
440459}
441460
442- /* call-seq: stmt.autoindexes
443- *
444- * Return the number of rows inserted into transient indices that were created automatically in order to help joins run faster
445- */
446- static VALUE
447- autoindexes (VALUE self )
461+ static size_t
462+ stmt_stat_internal (VALUE hash_or_sym , sqlite3_stmt * stmt )
448463{
449- sqlite3StmtRubyPtr ctx ;
450- TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
451- REQUIRE_OPEN_STMT (ctx );
464+ VALUE hash = Qnil , key = Qnil ;
452465
453- return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_AUTOINDEX , 0 ));
454- }
466+ setup_stmt_stat_symbols ();
455467
456- /* call-seq: stmt.vm_steps
457- *
458- * Return the number of virtual machine operations executed by the prepared statement
459- */
460- static VALUE
461- vm_steps (VALUE self )
462- {
463- sqlite3StmtRubyPtr ctx ;
464- TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
465- REQUIRE_OPEN_STMT (ctx );
468+ if (RB_TYPE_P (hash_or_sym , T_HASH )) {
469+ hash = hash_or_sym ;
470+ }
471+ else if (SYMBOL_P (hash_or_sym )) {
472+ key = hash_or_sym ;
473+ }
474+ else {
475+ rb_raise (rb_eTypeError , "non-hash or symbol argument" );
476+ }
466477
467- return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_VM_STEP , 0 ));
468- }
478+ #define SET (name , stat_type ) \
479+ if (key == stmt_stat_symbols[stmt_stat_sym_##name]) \
480+ return sqlite3_stmt_status(stmt, stat_type, 0); \
481+ else if (hash != Qnil) \
482+ rb_hash_aset(hash, stmt_stat_symbols[stmt_stat_sym_##name], SIZET2NUM(sqlite3_stmt_status(stmt, stat_type, 0)));
469483
484+ SET (fullscan_steps , SQLITE_STMTSTATUS_FULLSCAN_STEP );
485+ SET (sorts , SQLITE_STMTSTATUS_SORT );
486+ SET (autoindexes , SQLITE_STMTSTATUS_AUTOINDEX );
487+ SET (vm_steps , SQLITE_STMTSTATUS_VM_STEP );
470488#ifdef SQLITE_STMTSTATUS_REPREPARE
471- /* call-seq: stmt.reprepares
472- *
473- * Return the number of times that the prepare statement has been automatically regenerated due to schema changes or changes to bound parameters that might affect the query plan.
474- */
475- static VALUE
476- reprepares (VALUE self )
477- {
478- sqlite3StmtRubyPtr ctx ;
479- TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
480- REQUIRE_OPEN_STMT (ctx );
481-
482- return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_REPREPARE , 0 ));
483- }
489+ SET (reprepares , SQLITE_STMTSTATUS_REPREPARE );
484490#endif
485-
486491#ifdef SQLITE_STMTSTATUS_RUN
487- /* call-seq: stmt.runs
488- *
489- * Return the number of times that the prepared statement has been run
490- */
491- static VALUE
492- runs (VALUE self )
493- {
494- sqlite3StmtRubyPtr ctx ;
495- TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
496- REQUIRE_OPEN_STMT (ctx );
497-
498- return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_RUN , 0 ));
499- }
492+ SET (runs , SQLITE_STMTSTATUS_RUN );
500493#endif
501-
502494#ifdef SQLITE_STMTSTATUS_FILTER_MISS
503- /* call-seq: stmt. filter_misses
504- *
505- * Return the number of times that the Bloom filter returned a find, and thus the join step had to be processed as normal.
506- */
507- static VALUE
508- filter_misses ( VALUE self )
509- {
510- sqlite3StmtRubyPtr ctx ;
511- TypedData_Get_Struct ( self , sqlite3StmtRuby , & statement_type , ctx );
512- REQUIRE_OPEN_STMT ( ctx );
495+ SET ( filter_misses , SQLITE_STMTSTATUS_FILTER_MISS );
496+ #endif
497+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
498+ SET ( filter_hits , SQLITE_STMTSTATUS_FILTER_HIT );
499+ #endif
500+ #undef SET
501+
502+ if (! NIL_P ( key )) { /* matched key should return above */
503+ rb_raise ( rb_eArgError , "unknown key: %" PRIsVALUE , rb_sym2str ( key ) );
504+ }
513505
514- return INT2NUM ( sqlite3_stmt_status ( ctx -> st , SQLITE_STMTSTATUS_FILTER_MISS , 0 )) ;
506+ return 0 ;
515507}
516- #endif
517508
518- #ifdef SQLITE_STMTSTATUS_FILTER_HIT
519- /* call-seq: stmt.filter_hits
509+ /* call-seq: stmt.stmt_stat(hash_or_key)
520510 *
521- * Return the number of times that a join step was bypassed because a Bloom filter returned not-found
511+ * Returns a Hash containing information about the statement.
522512 */
523513static VALUE
524- filter_hits (VALUE self )
514+ stmt_stat (VALUE self , VALUE arg ) // arg is (nil || hash || symbol )
525515{
526516 sqlite3StmtRubyPtr ctx ;
527517 TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
528518 REQUIRE_OPEN_STMT (ctx );
529519
530- return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_FILTER_HIT , 0 ));
520+ if (NIL_P (arg )) {
521+ arg = rb_hash_new ();
522+ }
523+ else if (SYMBOL_P (arg )) {
524+ size_t value = stmt_stat_internal (arg , ctx -> st );
525+ return SIZET2NUM (value );
526+ }
527+ else if (RB_TYPE_P (arg , T_HASH )) {
528+ // ok
529+ }
530+ else {
531+ rb_raise (rb_eTypeError , "non-hash or symbol given" );
532+ }
533+
534+ stmt_stat_internal (arg , ctx -> st );
535+ return arg ;
531536}
532- #endif
533537
534538#ifdef SQLITE_STMTSTATUS_MEMUSED
535539/* call-seq: stmt.memory_used
@@ -583,33 +587,10 @@ init_sqlite3_statement(void)
583587 rb_define_method (cSqlite3Statement , "column_name" , column_name , 1 );
584588 rb_define_method (cSqlite3Statement , "column_decltype" , column_decltype , 1 );
585589 rb_define_method (cSqlite3Statement , "bind_parameter_count" , bind_parameter_count , 0 );
586- rb_define_method (cSqlite3Statement , "fullscan_steps" , fullscan_steps , 0 );
587- rb_define_method (cSqlite3Statement , "sorts" , sorts , 0 );
588- rb_define_method (cSqlite3Statement , "autoindexes" , autoindexes , 0 );
589- rb_define_method (cSqlite3Statement , "vm_steps" , vm_steps , 0 );
590- rb_define_private_method (cSqlite3Statement , "prepare" , prepare , 2 );
591-
592- #ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
593- rb_define_method (cSqlite3Statement , "database_name" , database_name , 1 );
594- #endif
595-
596- #ifdef SQLITE_STMTSTATUS_REPREPARE
597- rb_define_method (cSqlite3Statement , "reprepares" , reprepares , 0 );
598- #endif
599-
600- #ifdef SQLITE_STMTSTATUS_RUN
601- rb_define_method (cSqlite3Statement , "runs" , runs , 0 );
602- #endif
603-
604- #ifdef SQLITE_STMTSTATUS_FILTER_MISS
605- rb_define_method (cSqlite3Statement , "filter_misses" , filter_misses , 0 );
606- #endif
607-
608- #ifdef SQLITE_STMTSTATUS_FILTER_HIT
609- rb_define_method (cSqlite3Statement , "filter_hits" , filter_hits , 0 );
610- #endif
611-
590+ rb_define_method (cSqlite3Statement , "stmt_stat" , stmt_stat , 1 );
612591#ifdef SQLITE_STMTSTATUS_MEMUSED
613592 rb_define_method (cSqlite3Statement , "memused" , memused , 0 );
614593#endif
594+
595+ rb_define_private_method (cSqlite3Statement , "prepare" , prepare , 2 );
615596}
0 commit comments