@@ -460,6 +460,36 @@ bind_parameter_count(VALUE self)
460460 return INT2NUM (sqlite3_bind_parameter_count (ctx -> st ));
461461}
462462
463+ /** call-seq: stmt.named_params
464+ *
465+ * Return the list of named parameters in the statement.
466+ */
467+ static VALUE
468+ named_params (VALUE self )
469+ {
470+ sqlite3StmtRubyPtr ctx ;
471+ TypedData_Get_Struct (self , sqlite3StmtRuby , & statement_type , ctx );
472+
473+ REQUIRE_LIVE_DB (ctx );
474+ REQUIRE_OPEN_STMT (ctx );
475+
476+ int param_count = sqlite3_bind_parameter_count (ctx -> st );
477+ VALUE params = rb_ary_new2 (param_count );
478+
479+ // The first host parameter has an index of 1, not 0.
480+ for (int i = 1 ; i <= param_count ; i ++ ) {
481+ const char * name = sqlite3_bind_parameter_name (ctx -> st , i );
482+ // If parameters of the ?NNN form are used, there may be gaps in the list.
483+ if (name ) {
484+ VALUE rb_name = interned_utf8_cstr (name );
485+ // The initial ":" or "$" or "@" or "?" is included as part of the name.
486+ rb_name = rb_str_substr (rb_name , 1 , RSTRING_LEN (rb_name ) - 1 );
487+ rb_ary_push (params , rb_name );
488+ }
489+ }
490+ return rb_obj_freeze (params );
491+ }
492+
463493enum stmt_stat_sym {
464494 stmt_stat_sym_fullscan_steps ,
465495 stmt_stat_sym_sorts ,
@@ -689,6 +719,7 @@ init_sqlite3_statement(void)
689719 rb_define_method (cSqlite3Statement , "column_name" , column_name , 1 );
690720 rb_define_method (cSqlite3Statement , "column_decltype" , column_decltype , 1 );
691721 rb_define_method (cSqlite3Statement , "bind_parameter_count" , bind_parameter_count , 0 );
722+ rb_define_method (cSqlite3Statement , "named_params" , named_params , 0 );
692723 rb_define_method (cSqlite3Statement , "sql" , get_sql , 0 );
693724 rb_define_method (cSqlite3Statement , "expanded_sql" , get_expanded_sql , 0 );
694725#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
0 commit comments