Skip to content

Commit

Permalink
Move Statement#initialize to Ruby
Browse files Browse the repository at this point in the history
Move statement#initialize to Ruby so that we don't need to use C apis to
set instance variables
  • Loading branch information
tenderlove committed Jan 3, 2024
1 parent 4f8ff6f commit a9a89f8
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 32 deletions.
46 changes: 14 additions & 32 deletions ext/sqlite3/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,51 +31,33 @@ static VALUE allocate(VALUE klass)
return TypedData_Make_Struct(klass, sqlite3StmtRuby, &statement_type, ctx);
}

/* call-seq: SQLite3::Statement.new(db, sql)
*
* Create a new statement attached to the given Database instance, and which
* encapsulates the given SQL text. If the text contains more than one
* statement (i.e., separated by semicolons), then the #remainder property
* will be set to the trailing text.
*/
static VALUE initialize(VALUE self, VALUE db, VALUE sql)
static VALUE
prepare(VALUE self, VALUE db, VALUE sql)
{
sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
sqlite3StmtRubyPtr ctx;
const char *tail = NULL;
int status;

StringValue(sql);
sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
sqlite3StmtRubyPtr ctx;
const char *tail = NULL;
int status;

TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);

if(!db_ctx->db)
rb_raise(rb_eArgError, "prepare called on a closed database");
StringValue(sql);

if(!UTF8_P(sql)) {
sql = rb_str_export_to_enc(sql, rb_utf8_encoding());
}
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);

#ifdef HAVE_SQLITE3_PREPARE_V2
status = sqlite3_prepare_v2(
status = sqlite3_prepare_v2(
#else
status = sqlite3_prepare(
status = sqlite3_prepare(
#endif
db_ctx->db,
(const char *)StringValuePtr(sql),
(int)RSTRING_LEN(sql),
&ctx->st,
&tail
);
);

CHECK(db_ctx->db, status);
CHECK(db_ctx->db, status);

rb_iv_set(self, "@connection", db);
rb_iv_set(self, "@remainder", rb_str_new2(tail));
rb_iv_set(self, "@columns", Qnil);
rb_iv_set(self, "@types", Qnil);

return self;
return rb_str_new2(tail);
}

/* call-seq: stmt.close
Expand Down Expand Up @@ -432,7 +414,6 @@ void init_sqlite3_statement(void)
cSqlite3Statement = rb_define_class_under(mSqlite3, "Statement", rb_cObject);

rb_define_alloc_func(cSqlite3Statement, allocate);
rb_define_method(cSqlite3Statement, "initialize", initialize, 2);
rb_define_method(cSqlite3Statement, "close", sqlite3_rb_close, 0);
rb_define_method(cSqlite3Statement, "closed?", closed_p, 0);
rb_define_method(cSqlite3Statement, "bind_param", bind_param, 2);
Expand All @@ -444,6 +425,7 @@ void 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_private_method(cSqlite3Statement, "prepare", prepare, 2);

#ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
rb_define_method(cSqlite3Statement, "database_name", database_name, 1);
Expand Down
17 changes: 17 additions & 0 deletions lib/sqlite3/statement.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ class Statement
# this will be the empty string.
attr_reader :remainder

# call-seq: SQLite3::Statement.new(db, sql)
#
# Create a new statement attached to the given Database instance, and which
# encapsulates the given SQL text. If the text contains more than one
# statement (i.e., separated by semicolons), then the #remainder property
# will be set to the trailing text.
def initialize(db, sql)
raise ArgumentError, "pepare called on a closed database" if db.closed?

sql = sql.encode(Encoding::UTF_8) if sql && sql.encoding != Encoding::UTF_8

@connection = db
@columns = nil
@types = nil
@remainder = prepare db, sql
end

# Binds the given variables to the corresponding placeholders in the SQL
# text.
#
Expand Down

0 comments on commit a9a89f8

Please sign in to comment.