Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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