Skip to content

Commit

Permalink
Add sql and expanded_sql methods to the statement object
Browse files Browse the repository at this point in the history
These methods allow you to retrieve the SQL statement that was used to
create the statement object.  The `sql` method just returns the sql
statement, where the `expanded_sql` method returns the statement but
with bind parameters substituted.

This should aid with debugging and other tasks.

Fixes #293
  • Loading branch information
tenderlove committed Feb 1, 2024
1 parent 9b8dfb4 commit e2b15ee
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 0 deletions.
31 changes: 31 additions & 0 deletions ext/sqlite3/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,35 @@ database_name(VALUE self, VALUE index)

#endif

/* call-seq: stmt.sql
*
* Returns the SQL statement used to create this prepared statement
*/
static VALUE
get_sql(VALUE self)
{
sqlite3StmtRubyPtr ctx;
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
REQUIRE_OPEN_STMT(ctx);

return rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(sqlite3_sql(ctx->st)));
}

/* call-seq: stmt.expanded_sql
*
* Returns the SQL statement used to create this prepared statement, but
* with bind parameters substituted in to the statement.
*/
static VALUE
get_expanded_sql(VALUE self)
{
sqlite3StmtRubyPtr ctx;
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
REQUIRE_OPEN_STMT(ctx);

return rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(sqlite3_expanded_sql(ctx->st)));
}

void
init_sqlite3_statement(void)
{
Expand All @@ -615,6 +644,8 @@ 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, "sql", get_sql, 0);
rb_define_method(cSqlite3Statement, "expanded_sql", get_expanded_sql, 0);
#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
rb_define_method(cSqlite3Statement, "database_name", database_name, 1);
#endif
Expand Down
17 changes: 17 additions & 0 deletions test/test_statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ def test_column_names_are_deduped
stmt&.close
end

def test_sql_method
sql = "SELECT 1234"
stmt = @db.prepare sql
assert_equal sql, stmt.sql
ensure
stmt.close
end

def test_expanded_sql_method
sql = "SELECT ?"
stmt = @db.prepare sql
stmt.bind_params 1234
assert_equal "SELECT 1234", stmt.expanded_sql
ensure
stmt.close
end

def test_insert_duplicate_records
@db.execute 'CREATE TABLE "things" ("name" varchar(20) CONSTRAINT "index_things_on_name" UNIQUE)'
stmt = @db.prepare("INSERT INTO things(name) VALUES(?)")
Expand Down

0 comments on commit e2b15ee

Please sign in to comment.