diff --git a/SQLite.xs b/SQLite.xs index 6afa5cd..5a22008 100644 --- a/SQLite.xs +++ b/SQLite.xs @@ -44,16 +44,17 @@ last_insert_rowid(dbh) RETVAL static int -create_function(dbh, name, argc, func) +create_function(dbh, name, argc, func, flags = 0) SV *dbh char *name int argc SV *func + int flags ALIAS: DBD::SQLite::db::sqlite_create_function = 1 CODE: { - RETVAL = sqlite_db_create_function(aTHX_ dbh, name, argc, func ); + RETVAL = sqlite_db_create_function(aTHX_ dbh, name, argc, func, flags ); } OUTPUT: RETVAL @@ -90,16 +91,17 @@ load_extension(dbh, file, proc = 0) #endif static int -create_aggregate(dbh, name, argc, aggr) +create_aggregate(dbh, name, argc, aggr, flags = 0) SV *dbh char *name int argc SV *aggr + int flags ALIAS: DBD::SQLite::db::sqlite_create_aggregate = 1 CODE: { - RETVAL = sqlite_db_create_aggregate(aTHX_ dbh, name, argc, aggr ); + RETVAL = sqlite_db_create_aggregate(aTHX_ dbh, name, argc, aggr, flags ); } OUTPUT: RETVAL diff --git a/dbdimp.c b/dbdimp.c index edd333b..5676800 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -1698,7 +1698,7 @@ sqlite_db_func_dispatcher_no_unicode(sqlite3_context *context, int argc, sqlite3 } int -sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func) +sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func, int flags) { D_imp_dbh(dbh); int rc; @@ -1716,7 +1716,7 @@ sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func) croak_if_db_is_null(); /* warn("create_function %s with %d args\n", name, argc); */ - rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8, + rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8|flags, func_sv, imp_dbh->unicode ? sqlite_db_func_dispatcher_unicode : sqlite_db_func_dispatcher_no_unicode, @@ -1991,7 +1991,7 @@ sqlite_db_aggr_finalize_dispatcher( sqlite3_context *context ) } int -sqlite_db_create_aggregate(pTHX_ SV *dbh, const char *name, int argc, SV *aggr_pkg) +sqlite_db_create_aggregate(pTHX_ SV *dbh, const char *name, int argc, SV *aggr_pkg, int flags) { D_imp_dbh(dbh); int rc; @@ -2008,7 +2008,7 @@ sqlite_db_create_aggregate(pTHX_ SV *dbh, const char *name, int argc, SV *aggr_p croak_if_db_is_null(); - rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8, + rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8|flags, aggr_pkg_copy, NULL, sqlite_db_aggr_step_dispatcher, diff --git a/dbdimp.h b/dbdimp.h index 84f9558..1588b2f 100644 --- a/dbdimp.h +++ b/dbdimp.h @@ -95,14 +95,14 @@ struct aggrInfo { }; -int sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func); +int sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func, int flags); #ifndef SQLITE_OMIT_LOAD_EXTENSION int sqlite_db_enable_load_extension(pTHX_ SV *dbh, int onoff); int sqlite_db_load_extension(pTHX_ SV *dbh, const char *file, const char *proc); #endif -int sqlite_db_create_aggregate(pTHX_ SV *dbh, const char *name, int argc, SV *aggr ); +int sqlite_db_create_aggregate(pTHX_ SV *dbh, const char *name, int argc, SV *aggr, int flags ); int sqlite_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func); int sqlite_db_progress_handler(pTHX_ SV *dbh, int n_opcodes, SV *handler); int sqlite_bind_col( SV *sth, imp_sth_t *imp_sth, SV *col, SV *ref, IV sql_type, SV *attribs ); diff --git a/t/09_create_function.t b/t/09_create_function.t index a868b5b..6e4dac5 100644 --- a/t/09_create_function.t +++ b/t/09_create_function.t @@ -10,8 +10,15 @@ BEGIN { use t::lib::Test qw/connect_ok @CALL_FUNCS/; use Test::More; use Test::NoWarnings; +use DBD::SQLite; +use DBD::SQLite::Constants; -plan tests => 29 * @CALL_FUNCS + 1; +my @function_flags = (undef, 0); +if ($DBD::SQLite::sqlite_version_number >= 3008003) { + push @function_flags, DBD::SQLite::Constants::SQLITE_DETERMINISTIC; +} + +plan tests => 29 * @CALL_FUNCS * @function_flags + 1; sub now { return time(); @@ -53,10 +60,10 @@ sub noop { return $_[0]; } -foreach my $call_func (@CALL_FUNCS) { +foreach my $call_func (@CALL_FUNCS) { for my $flags (@function_flags) { my $dbh = connect_ok( PrintError => 0 ); - ok($dbh->$call_func( "now", 0, \&now, "create_function" )); + ok($dbh->$call_func( "now", 0, \&now, defined $flags ? $flags : (), "create_function" )); my $result = $dbh->selectrow_arrayref( "SELECT now()" ); ok( $result->[0], 'Got a result' ); @@ -65,35 +72,35 @@ foreach my $call_func (@CALL_FUNCS) { $dbh->do( 'INSERT INTO func_test VALUES ( 1, 3 )' ); $dbh->do( 'INSERT INTO func_test VALUES ( 0, 4 )' ); - ok($dbh->$call_func( "add2", 2, \&add2, "create_function" )); + ok($dbh->$call_func( "add2", 2, \&add2, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT add2(1,3)" ); is($result->[0], 4, "SELECT add2(1,3)" ); $result = $dbh->selectall_arrayref( "SELECT add2(a,b) FROM func_test" ); is_deeply( $result, [ [4], [4] ], "SELECT add2(a,b) FROM func_test" ); - ok($dbh->$call_func( "my_sum", -1, \&my_sum, "create_function" )); + ok($dbh->$call_func( "my_sum", -1, \&my_sum, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT my_sum( '2', 3, 4, '5')" ); is( $result->[0], 14, "SELECT my_sum( '2', 3, 4, '5')" ); - ok($dbh->$call_func( "error", -1, \&error, "create_function" )); + ok($dbh->$call_func( "error", -1, \&error, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT error( 'I died' )" ); ok( !$result ); like( $DBI::errstr, qr/function is dying: I died/ ); - ok($dbh->$call_func( "void_return", -1, \&void_return, "create_function" )); + ok($dbh->$call_func( "void_return", -1, \&void_return, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT void_return( 'I died' )" ); is_deeply( $result, [ undef ], "SELECT void_return( 'I died' )" ); - ok($dbh->$call_func( "return_null", -1, \&return_null, "create_function" )); + ok($dbh->$call_func( "return_null", -1, \&return_null, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT return_null()" ); is_deeply( $result, [ undef ], "SELECT return_null()" ); - ok($dbh->$call_func( "return2", -1, \&return2, "create_function" )); + ok($dbh->$call_func( "return2", -1, \&return2, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT return2()" ); is_deeply( $result, [ 2 ], "SELECT return2()" ); - ok($dbh->$call_func( "my_defined", 1, \&my_defined, "create_function" )); + ok($dbh->$call_func( "my_defined", 1, \&my_defined, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT my_defined(1)" ); is_deeply( $result, [ 1 ], "SELECT my_defined(1)" ); @@ -106,7 +113,7 @@ foreach my $call_func (@CALL_FUNCS) { $result = $dbh->selectrow_arrayref( "SELECT my_defined(NULL)" ); is_deeply( $result, [ '0' ], "SELECT my_defined(NULL)" ); - ok($dbh->$call_func( "noop", 1, \&noop, "create_function" )); + ok($dbh->$call_func( "noop", 1, \&noop, defined $flags ? $flags : (), "create_function" )); $result = $dbh->selectrow_arrayref( "SELECT noop(NULL)" ); is_deeply( $result, [ undef ], "SELECT noop(NULL)" ); @@ -127,4 +134,4 @@ foreach my $call_func (@CALL_FUNCS) { is_deeply( $result, [ 'integer' ], "SELECT typeof(noop(2147483648))" ); $dbh->disconnect; -} +}} diff --git a/t/10_create_aggregate.t b/t/10_create_aggregate.t index d796f22..ad7b644 100644 --- a/t/10_create_aggregate.t +++ b/t/10_create_aggregate.t @@ -9,8 +9,15 @@ BEGIN { use t::lib::Test qw/connect_ok @CALL_FUNCS/; use Test::More; use Test::NoWarnings; +use DBD::SQLite; +use DBD::SQLite::Constants; -plan tests => 21 * @CALL_FUNCS + 1; +my @function_flags = (undef, 0); +if ($DBD::SQLite::sqlite_version_number >= 3008003) { + push @function_flags, DBD::SQLite::Constants::SQLITE_DETERMINISTIC; +} + +plan tests => 21 * @CALL_FUNCS * @function_flags + 1; # Create the aggregate test packages SCOPE: { @@ -70,7 +77,7 @@ SCOPE: { } } -foreach my $call_func (@CALL_FUNCS) { +foreach my $call_func (@CALL_FUNCS) { for my $flags (@function_flags) { my $dbh = connect_ok( PrintError => 0 ); $dbh->do( "CREATE TABLE aggr_test ( field )" ); @@ -78,7 +85,7 @@ foreach my $call_func (@CALL_FUNCS) { $dbh->do( "INSERT INTO aggr_test VALUES ( $val )" ); } - ok($dbh->$call_func( "newcount", 0, "count_aggr", "create_aggregate" )); + ok($dbh->$call_func( "newcount", 0, "count_aggr", defined $flags ? $flags : (), "create_aggregate" )); my $result = $dbh->selectrow_arrayref( "SELECT newcount() FROM aggr_test" ); ok( $result && $result->[0] == 3 ); @@ -96,7 +103,7 @@ foreach my $call_func (@CALL_FUNCS) { $result = $dbh->selectrow_arrayref( "SELECT newcount() FROM aggr_empty_test" ); ok( $result && !$result->[0] ); - ok($dbh->$call_func( "defined", 1, 'obj_aggregate', "create_aggregate" )); + ok($dbh->$call_func( "defined", 1, 'obj_aggregate', defined $flags ? $flags : (), "create_aggregate" )); $result = $dbh->selectrow_arrayref( "SELECT defined(field) FROM aggr_test" ); ok( $result && $result->[0] == 2 ); $result = $dbh->selectrow_arrayref( "SELECT defined(field) FROM aggr_test" ); @@ -111,7 +118,7 @@ foreach my $call_func (@CALL_FUNCS) { foreach my $fail ( qw/ new step finalize/ ) { $last_warn = ''; my $aggr = fail_aggregate->new( $fail ); - ok($dbh->$call_func( "fail_$fail", -1, $aggr, 'create_aggregate' )); + ok($dbh->$call_func( "fail_$fail", -1, $aggr, defined $flags ? $flags : (), 'create_aggregate' )); $result = $dbh->selectrow_arrayref( "SELECT fail_$fail() FROM aggr_test" ); # ok( !$result && $DBI::errstr =~ /$fail\(\) failed on request/ ); ok( !defined $result->[0] && $last_warn =~ /$fail\(\) failed on request/ ); @@ -126,10 +133,10 @@ foreach my $call_func (@CALL_FUNCS) { my $aggr = fail_aggregate->new( 'undef' ); $last_warn = ''; - ok($dbh->$call_func( "fail_undef", -1, $aggr, 'create_aggregate' )); + ok($dbh->$call_func( "fail_undef", -1, $aggr, defined $flags ? $flags : (), 'create_aggregate' )); $result = $dbh->selectrow_arrayref( "SELECT fail_undef() FROM aggr_test" ); # ok( !$result && $DBI::errstr =~ /new\(\) should return a blessed reference/ ); ok( !defined $result->[0] && $last_warn =~ /new\(\) should return a blessed reference/ ); $dbh->disconnect; -} +}}