Skip to content

Commit 2c92405

Browse files
authored
Merge pull request #642 from captn3m0/stmt-named-params
Implements stmt.named_params
2 parents 7e6319a + 94746f4 commit 2c92405

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

FAQ.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,17 @@ Placeholders in an SQL statement take any of the following formats:
122122
* `?`
123123
* `?_nnn_`
124124
* `:_word_`
125+
* `$_word_`
126+
* `@_word_`
125127

126128

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

135137

136138
For example, here is a query using these placeholder formats:

ext/sqlite3/statement.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,40 @@ 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+
* This returns a frozen array of strings (without the leading prefix character).
467+
* The values of this list can be used to bind parameters
468+
* to the statement using bind_param. Positional (?NNN) and anonymous (?)
469+
* parameters are excluded.
470+
*
471+
*/
472+
static VALUE
473+
named_params(VALUE self)
474+
{
475+
sqlite3StmtRubyPtr ctx;
476+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
477+
478+
REQUIRE_LIVE_DB(ctx);
479+
REQUIRE_OPEN_STMT(ctx);
480+
481+
int param_count = sqlite3_bind_parameter_count(ctx->st);
482+
VALUE params = rb_ary_new2(param_count);
483+
484+
// The first host parameter has an index of 1, not 0.
485+
for (int i = 1; i <= param_count; i++) {
486+
const char *name = sqlite3_bind_parameter_name(ctx->st, i);
487+
// We ignore positional and anonymous parameters, and also null values, since there can be
488+
// gaps in the list.
489+
if (name && *name != '?') {
490+
VALUE param = interned_utf8_cstr(name + 1);
491+
rb_ary_push(params, param);
492+
}
493+
}
494+
return rb_obj_freeze(params);
495+
}
496+
463497
enum stmt_stat_sym {
464498
stmt_stat_sym_fullscan_steps,
465499
stmt_stat_sym_sorts,
@@ -689,6 +723,7 @@ init_sqlite3_statement(void)
689723
rb_define_method(cSqlite3Statement, "column_name", column_name, 1);
690724
rb_define_method(cSqlite3Statement, "column_decltype", column_decltype, 1);
691725
rb_define_method(cSqlite3Statement, "bind_parameter_count", bind_parameter_count, 0);
726+
rb_define_method(cSqlite3Statement, "named_params", named_params, 0);
692727
rb_define_method(cSqlite3Statement, "sql", get_sql, 0);
693728
rb_define_method(cSqlite3Statement, "expanded_sql", get_expanded_sql, 0);
694729
#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME

test/test_statement.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,12 @@ def test_named_bind_not_found
256256
stmt.close
257257
end
258258

259+
def test_params
260+
stmt = SQLite3::Statement.new(@db, "select ?1, :foo, ?, $bar, @zed, ?250, @999, :123, $777")
261+
assert_equal ["foo", "bar", "zed", "999", "123", "777"], stmt.named_params
262+
stmt.close
263+
end
264+
259265
def test_each
260266
r = nil
261267
@stmt.each do |row|

0 commit comments

Comments
 (0)