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
16 changes: 9 additions & 7 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,17 @@ Placeholders in an SQL statement take any of the following formats:
* `?`
* `?_nnn_`
* `:_word_`
* `$_word_`
* `@_word_`


Where _n_ is an integer, and _word_ is an alpha-numeric identifier (or
number). When the placeholder is associated with a number, that number
identifies the index of the bind variable to replace it with. When it
is an identifier, it identifies the name of the corresponding bind
variable. (In the instance of the first format--a single question
mark--the placeholder is assigned a number one greater than the last
index used, or 1 if it is the first.)
Where _n_ is an integer, and _word_ is an alpha-numeric identifier(or number).
When the placeholder is associated with a number (only in case of `?_nnn_`),
that number identifies the index of the bind variable to replace it with.
When it is an identifier, it identifies the name of the corresponding bind
variable. (In the instance of the first format--a single question mark--the
placeholder is assigned a number one greater than the last index used, or 1
if it is the first.)


For example, here is a query using these placeholder formats:
Expand Down
36 changes: 36 additions & 0 deletions ext/sqlite3/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,41 @@ 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);
// We ignore numbered parameters (starting with ?)
// And null values, since there can be gaps in the list
if (name && *name != '?') {
// We ignore numeric parameters
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 +724,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, :123, $777")
assert_equal ["foo", "bar", "zed", "999", "123", "777"], stmt.named_params
stmt.close
end

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