Skip to content

Commit

Permalink
Merge pull request #432 from casperisfine/typed-data
Browse files Browse the repository at this point in the history
Convert SQLite3 objects to TypedData API
  • Loading branch information
flavorjones authored Nov 30, 2023
2 parents 61d8e1f + 4edffc3 commit 81cd2d7
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 63 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
37 changes: 25 additions & 12 deletions ext/sqlite3/backup.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,29 @@

VALUE cSqlite3Backup;

static void deallocate(void * ctx)
static size_t backup_memsize(const void *data)
{
sqlite3BackupRubyPtr c = (sqlite3BackupRubyPtr)ctx;
xfree(c);
sqlite3BackupRubyPtr ctx = (sqlite3BackupRubyPtr)data;
// NB: can't account for ctx->p because the type is incomplete.
return sizeof(*ctx);
}

static const rb_data_type_t backup_type = {
"SQLite3::Backup",
{
NULL,
RUBY_TYPED_DEFAULT_FREE,
backup_memsize,
},
0,
0,
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};

static VALUE allocate(VALUE klass)
{
sqlite3BackupRubyPtr ctx = xcalloc((size_t)1, sizeof(sqlite3BackupRuby));
return Data_Wrap_Struct(klass, NULL, deallocate, ctx);
sqlite3BackupRubyPtr ctx;
return TypedData_Make_Struct(klass, sqlite3BackupRuby, &backup_type, ctx);
}

/* call-seq: SQLite3::Backup.new(dstdb, dstname, srcdb, srcname)
Expand Down Expand Up @@ -62,9 +75,9 @@ static VALUE initialize(VALUE self, VALUE dstdb, VALUE dstname, VALUE srcdb, VAL
sqlite3RubyPtr ddb_ctx, sdb_ctx;
sqlite3_backup *pBackup;

Data_Get_Struct(self, sqlite3BackupRuby, ctx);
Data_Get_Struct(dstdb, sqlite3Ruby, ddb_ctx);
Data_Get_Struct(srcdb, sqlite3Ruby, sdb_ctx);
TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, 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 Expand Up @@ -97,7 +110,7 @@ static VALUE step(VALUE self, VALUE nPage)
sqlite3BackupRubyPtr ctx;
int status;

Data_Get_Struct(self, sqlite3BackupRuby, ctx);
TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
REQUIRE_OPEN_BACKUP(ctx);
status = sqlite3_backup_step(ctx->p, NUM2INT(nPage));
return INT2NUM(status);
Expand All @@ -111,7 +124,7 @@ static VALUE finish(VALUE self)
{
sqlite3BackupRubyPtr ctx;

Data_Get_Struct(self, sqlite3BackupRuby, ctx);
TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
REQUIRE_OPEN_BACKUP(ctx);
(void)sqlite3_backup_finish(ctx->p);
ctx->p = NULL;
Expand All @@ -129,7 +142,7 @@ static VALUE remaining(VALUE self)
{
sqlite3BackupRubyPtr ctx;

Data_Get_Struct(self, sqlite3BackupRuby, ctx);
TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
REQUIRE_OPEN_BACKUP(ctx);
return INT2NUM(sqlite3_backup_remaining(ctx->p));
}
Expand All @@ -145,7 +158,7 @@ static VALUE pagecount(VALUE self)
{
sqlite3BackupRubyPtr ctx;

Data_Get_Struct(self, sqlite3BackupRuby, ctx);
TypedData_Get_Struct(self, sqlite3BackupRuby, &backup_type, ctx);
REQUIRE_OPEN_BACKUP(ctx);
return INT2NUM(sqlite3_backup_pagecount(ctx->p));
}
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
Loading

0 comments on commit 81cd2d7

Please sign in to comment.