Skip to content

Commit

Permalink
Convert SQLite3::Database objects to TypedData API
Browse files Browse the repository at this point in the history
The replacement API was introduced in Ruby 1.9.2 (2010),
and the old untyped data API was marked a deprecated in the documentation
as of Ruby 2.3.0 (2015)

Ref: https://bugs.ruby-lang.org/issues/19998
  • Loading branch information
byroot committed Nov 30, 2023
1 parent f2ad911 commit 11cfff1
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 32 deletions.
3 changes: 1 addition & 2 deletions ext/sqlite3/aggregator.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,11 @@ VALUE
rb_sqlite3_define_aggregator2(VALUE self, VALUE aggregator, VALUE ruby_name)
{
/* define_aggregator is added as a method to SQLite3::Database in database.c */
sqlite3RubyPtr ctx;
sqlite3RubyPtr ctx = sqlite3_database_unwrap(self);
int arity, status;
VALUE aw;
VALUE aggregators;

Data_Get_Struct(self, sqlite3Ruby, ctx);
if (!ctx->db) {
rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed database");
}
Expand Down
4 changes: 2 additions & 2 deletions ext/sqlite3/backup.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ static VALUE initialize(VALUE self, VALUE dstdb, VALUE dstname, VALUE srcdb, VAL
sqlite3_backup *pBackup;

TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
Data_Get_Struct(dstdb, sqlite3Ruby, ddb_ctx);
Data_Get_Struct(srcdb, sqlite3Ruby, sdb_ctx);
ddb_ctx = sqlite3_database_unwrap(dstdb);
sdb_ctx = sqlite3_database_unwrap(srcdb);

if(!sdb_ctx->db)
rb_raise(rb_eArgError, "cannot backup from a closed database");
Expand Down
77 changes: 51 additions & 26 deletions ext/sqlite3/database.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,29 @@ static void deallocate(void * ctx)
xfree(c);
}

static size_t database_memsize(const void *ctx)
{
const sqlite3RubyPtr c = (const sqlite3RubyPtr)ctx;
// NB: can't account for ctx->db because the type is incomplete.
return sizeof(*c);
}

static const rb_data_type_t database_type = {
"SQLite3::Backup",
{
NULL,
deallocate,
database_memsize,
},
0,
0,
RUBY_TYPED_WB_PROTECTED, // Not freed immediately because the dfree function do IOs.
};

static VALUE allocate(VALUE klass)
{
sqlite3RubyPtr ctx = xcalloc((size_t)1, sizeof(sqlite3Ruby));
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
sqlite3RubyPtr ctx;
return TypedData_Make_Struct(klass, sqlite3Ruby, &database_type, ctx);
}

static char *
Expand All @@ -37,12 +56,18 @@ utf16_string_value_ptr(VALUE str)

static VALUE sqlite3_rb_close(VALUE self);

sqlite3RubyPtr sqlite3_database_unwrap(VALUE database){
sqlite3RubyPtr ctx;
TypedData_Get_Struct(database, sqlite3Ruby, &database_type, ctx);
return ctx;
}

static VALUE rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs)
{
sqlite3RubyPtr ctx;
int status;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);

#if defined TAINTING_SUPPORT
# if defined StringValueCStr
Expand All @@ -69,7 +94,7 @@ static VALUE rb_sqlite3_disable_quirk_mode(VALUE self)
{
#if defined SQLITE_DBCONFIG_DQS_DDL
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);

if(!ctx->db) return Qfalse;

Expand All @@ -90,7 +115,7 @@ static VALUE sqlite3_rb_close(VALUE self)
{
sqlite3RubyPtr ctx;
sqlite3 * db;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);

db = ctx->db;
CHECK(db, sqlite3_close(ctx->db));
Expand All @@ -109,7 +134,7 @@ static VALUE sqlite3_rb_close(VALUE self)
static VALUE closed_p(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);

if(!ctx->db) return Qtrue;

Expand All @@ -124,7 +149,7 @@ static VALUE closed_p(VALUE self)
static VALUE total_changes(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

return INT2NUM(sqlite3_total_changes(ctx->db));
Expand All @@ -150,7 +175,7 @@ static VALUE trace(int argc, VALUE *argv, VALUE self)
sqlite3RubyPtr ctx;
VALUE block;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

rb_scan_args(argc, argv, "01", &block);
Expand Down Expand Up @@ -195,7 +220,7 @@ static VALUE busy_handler(int argc, VALUE *argv, VALUE self)
VALUE block;
int status;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

rb_scan_args(argc, argv, "01", &block);
Expand All @@ -220,7 +245,7 @@ static VALUE busy_handler(int argc, VALUE *argv, VALUE self)
static VALUE last_insert_row_id(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
Expand Down Expand Up @@ -340,7 +365,7 @@ static VALUE define_function_with_flags(VALUE self, VALUE name, VALUE flags)
VALUE block;
int status;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

block = rb_block_proc();
Expand Down Expand Up @@ -380,7 +405,7 @@ static VALUE define_function(VALUE self, VALUE name)
static VALUE interrupt(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

sqlite3_interrupt(ctx->db);
Expand All @@ -396,7 +421,7 @@ static VALUE interrupt(VALUE self)
static VALUE errmsg(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

return rb_str_new2(sqlite3_errmsg(ctx->db));
Expand All @@ -410,7 +435,7 @@ static VALUE errmsg(VALUE self)
static VALUE errcode_(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

return INT2NUM(sqlite3_errcode(ctx->db));
Expand Down Expand Up @@ -438,7 +463,7 @@ static VALUE complete_p(VALUE UNUSED(self), VALUE sql)
static VALUE changes(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

return INT2NUM(sqlite3_changes(ctx->db));
Expand Down Expand Up @@ -483,7 +508,7 @@ static VALUE set_authorizer(VALUE self, VALUE authorizer)
sqlite3RubyPtr ctx;
int status;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

status = sqlite3_set_authorizer(
Expand All @@ -510,7 +535,7 @@ static VALUE set_authorizer(VALUE self, VALUE authorizer)
static VALUE set_busy_timeout(VALUE self, VALUE timeout)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

CHECK(ctx->db, sqlite3_busy_timeout(ctx->db, (int)NUM2INT(timeout)));
Expand All @@ -526,7 +551,7 @@ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
static VALUE set_extended_result_codes(VALUE self, VALUE enable)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

CHECK(ctx->db, sqlite3_extended_result_codes(ctx->db, RTEST(enable) ? 1 : 0));
Expand Down Expand Up @@ -571,7 +596,7 @@ int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const v
static VALUE collation(VALUE self, VALUE name, VALUE comparator)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

CHECK(ctx->db, sqlite3_create_collation(
Expand Down Expand Up @@ -600,7 +625,7 @@ static VALUE load_extension(VALUE self, VALUE file)
int status;
char *errMsg;
VALUE errexp;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

status = sqlite3_load_extension(ctx->db, StringValuePtr(file), 0, &errMsg);
Expand All @@ -624,7 +649,7 @@ static VALUE enable_load_extension(VALUE self, VALUE onoff)
{
sqlite3RubyPtr ctx;
int onoffparam;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

if (Qtrue == onoff) {
Expand Down Expand Up @@ -661,7 +686,7 @@ static VALUE db_encoding(VALUE self)
sqlite3RubyPtr ctx;
VALUE enc;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

enc = rb_iv_get(self, "@encoding");
Expand All @@ -681,7 +706,7 @@ static VALUE db_encoding(VALUE self)
static VALUE transaction_active_p(VALUE self)
{
sqlite3RubyPtr ctx;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
Expand Down Expand Up @@ -740,7 +765,7 @@ static VALUE exec_batch(VALUE self, VALUE sql, VALUE results_as_hash)
char *errMsg;
VALUE errexp;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

if(results_as_hash == Qtrue) {
Expand Down Expand Up @@ -768,7 +793,7 @@ static VALUE db_filename(VALUE self, VALUE db_name)
{
sqlite3RubyPtr ctx;
const char * fname;
Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
REQUIRE_OPEN_DB(ctx);

fname = sqlite3_db_filename(ctx->db, StringValueCStr(db_name));
Expand All @@ -782,7 +807,7 @@ static VALUE rb_sqlite3_open16(VALUE self, VALUE file)
int status;
sqlite3RubyPtr ctx;

Data_Get_Struct(self, sqlite3Ruby, ctx);
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);

#if defined TAINTING_SUPPORT
#if defined StringValueCStr
Expand Down
2 changes: 2 additions & 0 deletions ext/sqlite3/database.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ typedef sqlite3Ruby * sqlite3RubyPtr;

void init_sqlite3_database();
void set_sqlite3_func_result(sqlite3_context * ctx, VALUE result);

sqlite3RubyPtr sqlite3_database_unwrap(VALUE database);
VALUE sqlite3val2rb(sqlite3_value * val);

#endif
3 changes: 1 addition & 2 deletions ext/sqlite3/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ static VALUE allocate(VALUE klass)
*/
static VALUE initialize(VALUE self, VALUE db, VALUE sql)
{
sqlite3RubyPtr db_ctx;
sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
sqlite3StmtRubyPtr ctx;
const char *tail = NULL;
int status;

StringValue(sql);

Data_Get_Struct(db, sqlite3Ruby, db_ctx);
Data_Get_Struct(self, sqlite3StmtRuby, ctx);

if(!db_ctx->db)
Expand Down

0 comments on commit 11cfff1

Please sign in to comment.