Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ Placeholders in an SQL statement take any of the following formats:
* `?`
* `?_nnn_`
* `:_word_`
* `:_nnn_`
* `$_word_`
* `$_nnn_`
* `@_word_`
* `@_nnn_`


Where _n_ is an integer, and _word_ is an alpha-numeric identifier (or
Expand Down
39 changes: 39 additions & 0 deletions ext/sqlite3/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,44 @@ bind_parameter_count(VALUE self)
return INT2NUM(sqlite3_bind_parameter_count(ctx->st));
}

/** call-seq: stmt.params
*
* Return the list of named alphanumeric parameters in the statement.
* This returns a list of strings.
* The values of this list can be used to bind parameters
* to the statement using bind_param. Numeric and anonymous parameters
* are ignored.
*
*/
static VALUE
named_params(VALUE self)
{
sqlite3StmtRubyPtr ctx;
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);

REQUIRE_LIVE_DB(ctx);
REQUIRE_OPEN_STMT(ctx);

int param_count = sqlite3_bind_parameter_count(ctx->st);
VALUE params = rb_ary_new2(param_count);

// The first host parameter has an index of 1, not 0.
for (int i = 1; i <= param_count; i++) {
const char *name = sqlite3_bind_parameter_name(ctx->st, i);
// If parameters of the ?NNN/$NNN/@NNN/:NNN form are used
// there may be gaps in the list.
if (name) {
// We ignore numeric parameters
int n = atoi(name + 1);
if (n == 0) {
VALUE param = interned_utf8_cstr(name + 1);
rb_ary_push(params, param);
}
}
}
return rb_obj_freeze(params);
}

enum stmt_stat_sym {
stmt_stat_sym_fullscan_steps,
stmt_stat_sym_sorts,
Expand Down Expand Up @@ -689,6 +727,7 @@ init_sqlite3_statement(void)
rb_define_method(cSqlite3Statement, "column_name", column_name, 1);
rb_define_method(cSqlite3Statement, "column_decltype", column_decltype, 1);
rb_define_method(cSqlite3Statement, "bind_parameter_count", bind_parameter_count, 0);
rb_define_method(cSqlite3Statement, "named_params", named_params, 0);
rb_define_method(cSqlite3Statement, "sql", get_sql, 0);
rb_define_method(cSqlite3Statement, "expanded_sql", get_expanded_sql, 0);
#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
Expand Down
6 changes: 6 additions & 0 deletions test/test_statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,12 @@ def test_named_bind_not_found
stmt.close
end

def test_params
stmt = SQLite3::Statement.new(@db, "select ?1, :foo, ?, $bar, @zed, ?250, @999")
assert_equal ["foo", "bar", "zed"], stmt.named_params
stmt.close
end

def test_each
r = nil
@stmt.each do |row|
Expand Down
Loading