@@ -417,6 +417,153 @@ bind_parameter_count(VALUE self)
417417 return INT2NUM (sqlite3_bind_parameter_count (ctx -> st ));
418418}
419419
420+ enum stmt_stat_sym {
421+ stmt_stat_sym_fullscan_steps ,
422+ stmt_stat_sym_sorts ,
423+ stmt_stat_sym_autoindexes ,
424+ stmt_stat_sym_vm_steps ,
425+ #ifdef SQLITE_STMTSTATUS_REPREPARE
426+ stmt_stat_sym_reprepares ,
427+ #endif
428+ #ifdef SQLITE_STMTSTATUS_RUN
429+ stmt_stat_sym_runs ,
430+ #endif
431+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
432+ stmt_stat_sym_filter_misses ,
433+ #endif
434+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
435+ stmt_stat_sym_filter_hits ,
436+ #endif
437+ stmt_stat_sym_last
438+ };
439+
440+ static VALUE stmt_stat_symbols [stmt_stat_sym_last ];
441+
442+ static void
443+ setup_stmt_stat_symbols (void )
444+ {
445+ if (stmt_stat_symbols [0 ] == 0 ) {
446+ #define S (s ) stmt_stat_symbols[stmt_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
447+ S (fullscan_steps );
448+ S (sorts );
449+ S (autoindexes );
450+ S (vm_steps );
451+ #ifdef SQLITE_STMTSTATUS_REPREPARE
452+ S (reprepares );
453+ #endif
454+ #ifdef SQLITE_STMTSTATUS_RUN
455+ S (runs );
456+ #endif
457+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
458+ S (filter_misses );
459+ #endif
460+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
461+ S (filter_hits );
462+ #endif
463+ #undef S
464+ }
465+ }
466+
467+ static size_t
468+ stmt_stat_internal (VALUE hash_or_sym , sqlite3_stmt * stmt )
469+ {
470+ VALUE hash = Qnil , key = Qnil ;
471+
472+ setup_stmt_stat_symbols ();
473+
474+ if (RB_TYPE_P (hash_or_sym , T_HASH )) {
475+ hash = hash_or_sym ;
476+ }
477+ else if (SYMBOL_P (hash_or_sym )) {
478+ key = hash_or_sym ;
479+ }
480+ else {
481+ rb_raise (rb_eTypeError , "non-hash or symbol argument" );
482+ }
483+
484+ #define SET (name , stat_type ) \
485+ if (key == stmt_stat_symbols[stmt_stat_sym_##name]) \
486+ return sqlite3_stmt_status(stmt, stat_type, 0); \
487+ else if (hash != Qnil) \
488+ rb_hash_aset(hash, stmt_stat_symbols[stmt_stat_sym_##name], SIZET2NUM(sqlite3_stmt_status(stmt, stat_type, 0)));
489+
490+ SET (fullscan_steps , SQLITE_STMTSTATUS_FULLSCAN_STEP );
491+ SET (sorts , SQLITE_STMTSTATUS_SORT );
492+ SET (autoindexes , SQLITE_STMTSTATUS_AUTOINDEX );
493+ SET (vm_steps , SQLITE_STMTSTATUS_VM_STEP );
494+ #ifdef SQLITE_STMTSTATUS_REPREPARE
495+ SET (reprepares , SQLITE_STMTSTATUS_REPREPARE );
496+ #endif
497+ #ifdef SQLITE_STMTSTATUS_RUN
498+ SET (runs , SQLITE_STMTSTATUS_RUN );
499+ #endif
500+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
501+ SET (filter_misses , SQLITE_STMTSTATUS_FILTER_MISS );
502+ #endif
503+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
504+ SET (filter_hits , SQLITE_STMTSTATUS_FILTER_HIT );
505+ #endif
506+ #undef SET
507+
508+ if (!NIL_P (key )) { /* matched key should return above */
509+ rb_raise (rb_eArgError , "unknown key: %" PRIsVALUE , rb_sym2str (key ));
510+ }
511+
512+ return 0 ;
513+ }
514+
515+ /* call-seq: stmt.stats_as_hash(hash)
516+ *
517+ * Returns a Hash containing information about the statement.
518+ */
519+ static VALUE
520+ stats_as_hash (VALUE self )
521+ {
522+ sqlite3StmtRubyPtr ctx ;
523+ TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
524+ REQUIRE_OPEN_STMT (ctx );
525+ VALUE arg = rb_hash_new ();
526+
527+ stmt_stat_internal (arg , ctx -> st );
528+ return arg ;
529+ }
530+
531+ /* call-seq: stmt.stmt_stat(hash_or_key)
532+ *
533+ * Returns a Hash containing information about the statement.
534+ */
535+ static VALUE
536+ stat_for (VALUE self , VALUE key )
537+ {
538+ sqlite3StmtRubyPtr ctx ;
539+ TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
540+ REQUIRE_OPEN_STMT (ctx );
541+
542+ if (SYMBOL_P (key )) {
543+ size_t value = stmt_stat_internal (key , ctx -> st );
544+ return SIZET2NUM (value );
545+ }
546+ else {
547+ rb_raise (rb_eTypeError , "non-symbol given" );
548+ }
549+ }
550+
551+ #ifdef SQLITE_STMTSTATUS_MEMUSED
552+ /* call-seq: stmt.memory_used
553+ *
554+ * Return the approximate number of bytes of heap memory used to store the prepared statement
555+ */
556+ static VALUE
557+ memused (VALUE self )
558+ {
559+ sqlite3StmtRubyPtr ctx ;
560+ TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
561+ REQUIRE_OPEN_STMT (ctx );
562+
563+ return INT2NUM (sqlite3_stmt_status (ctx -> st , SQLITE_STMTSTATUS_MEMUSED , 0 ));
564+ }
565+ #endif
566+
420567#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
421568
422569/* call-seq: stmt.database_name(column_index)
@@ -453,9 +600,14 @@ init_sqlite3_statement(void)
453600 rb_define_method (cSqlite3Statement , "column_name" , column_name , 1 );
454601 rb_define_method (cSqlite3Statement , "column_decltype" , column_decltype , 1 );
455602 rb_define_method (cSqlite3Statement , "bind_parameter_count" , bind_parameter_count , 0 );
456- rb_define_private_method (cSqlite3Statement , "prepare" , prepare , 2 );
457-
458603#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
459604 rb_define_method (cSqlite3Statement , "database_name" , database_name , 1 );
460605#endif
606+ #ifdef SQLITE_STMTSTATUS_MEMUSED
607+ rb_define_method (cSqlite3Statement , "memused" , memused , 0 );
608+ #endif
609+
610+ rb_define_private_method (cSqlite3Statement , "prepare" , prepare , 2 );
611+ rb_define_private_method (cSqlite3Statement , "stats_as_hash" , stats_as_hash , 0 );
612+ rb_define_private_method (cSqlite3Statement , "stat_for" , stat_for , 1 );
461613}
0 commit comments