Skip to content

Commit 90f69da

Browse files
committed
the authorizer function can be set
1 parent 6c16f6c commit 90f69da

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

ext/sqlite3/database.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self)
4848
rb_raise(rb_eRuntimeError, "%s", sqlite3_errmsg(ctx->db));
4949

5050
rb_iv_set(self, "@tracefunc", Qnil);
51+
rb_iv_set(self, "@authorizer", Qnil);
5152

5253
if(rb_block_given_p()) {
5354
rb_yield(self);
@@ -382,6 +383,53 @@ static VALUE changes(VALUE self)
382383
return INT2NUM(sqlite3_changes(ctx->db));
383384
}
384385

386+
static int rb_sqlite3_auth(
387+
void *ctx,
388+
int _action,
389+
const char * _a,
390+
const char * _b,
391+
const char * _c,
392+
const char * _d)
393+
{
394+
VALUE self = (VALUE)ctx;
395+
VALUE action = INT2NUM(_action);
396+
VALUE a = _a ? rb_str_new2(_a) : Qnil;
397+
VALUE b = _b ? rb_str_new2(_b) : Qnil;
398+
VALUE c = _c ? rb_str_new2(_c) : Qnil;
399+
VALUE d = _d ? rb_str_new2(_d) : Qnil;
400+
VALUE callback = rb_iv_get(self, "@authorizer");
401+
VALUE result = rb_funcall(callback, rb_intern("call"), 5, action, a, b, c, d);
402+
403+
if(T_FIXNUM == TYPE(result)) return (int)NUM2INT(result);
404+
if(Qtrue == result) return SQLITE_OK;
405+
if(Qfalse == result) return SQLITE_DENY;
406+
407+
return SQLITE_IGNORE;
408+
}
409+
410+
/* call-seq: set_authorizer = auth
411+
*
412+
* Set the authorizer for this database. +auth+ must respond to +call+, and
413+
* +call+ must take 5 arguments.
414+
*/
415+
static VALUE set_authorizer(VALUE self, VALUE authorizer)
416+
{
417+
sqlite3RubyPtr ctx;
418+
Data_Get_Struct(self, sqlite3Ruby, ctx);
419+
REQUIRE_OPEN_DB(ctx);
420+
421+
int status = sqlite3_set_authorizer(
422+
ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)self
423+
);
424+
425+
if(SQLITE_OK != status)
426+
rb_raise(rb_eRuntimeError, "%s", sqlite3_errmsg(ctx->db));
427+
428+
rb_iv_set(self, "@authorizer", authorizer);
429+
430+
return self;
431+
}
432+
385433
void init_sqlite3_database()
386434
{
387435
cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
@@ -400,4 +448,5 @@ void init_sqlite3_database()
400448
rb_define_method(cSqlite3Database, "errcode", errcode, 0);
401449
rb_define_method(cSqlite3Database, "complete?", complete_p, 1);
402450
rb_define_method(cSqlite3Database, "changes", changes, 0);
451+
rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
403452
}

test/test_database.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,5 +176,46 @@ def step a
176176
value = @db.get_first_value( "select accumulate(a) from foo" )
177177
assert_equal 6, value
178178
end
179+
180+
def test_authorizer_ok
181+
@db.authorizer = Class.new {
182+
def call action, a, b, c, d; true end
183+
}.new
184+
@db.prepare("select 'fooooo'")
185+
186+
@db.authorizer = Class.new {
187+
def call action, a, b, c, d; 0 end
188+
}.new
189+
@db.prepare("select 'fooooo'")
190+
end
191+
192+
def test_authorizer_ignore
193+
@db.authorizer = Class.new {
194+
def call action, a, b, c, d; nil end
195+
}.new
196+
stmt = @db.prepare("select 'fooooo'")
197+
assert_equal nil, stmt.step
198+
end
199+
200+
def test_authorizer_fail
201+
@db.authorizer = Class.new {
202+
def call action, a, b, c, d; false end
203+
}.new
204+
assert_raises(SQLite3::SQLException) do
205+
@db.prepare("select 'fooooo'")
206+
end
207+
end
208+
209+
def test_remove_auth
210+
@db.authorizer = Class.new {
211+
def call action, a, b, c, d; false end
212+
}.new
213+
assert_raises(SQLite3::SQLException) do
214+
@db.prepare("select 'fooooo'")
215+
end
216+
217+
@db.authorizer = nil
218+
@db.prepare("select 'fooooo'")
219+
end
179220
end
180221
end

0 commit comments

Comments
 (0)