From 4d1b28c393fd8ccf7fb8b1e485e371caedec9605 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Sun, 6 Dec 2020 02:00:27 +0900 Subject: [PATCH] Expose sqlite3_txn_state --- SQLite.xs | 11 +++++++++++ dbdimp.c | 15 +++++++++++++++ dbdimp.h | 1 + lib/DBD/SQLite.pm | 9 +++++++++ t/67_txn_state.t | 41 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 t/67_txn_state.t diff --git a/SQLite.xs b/SQLite.xs index 122de79..48f113d 100644 --- a/SQLite.xs +++ b/SQLite.xs @@ -380,6 +380,17 @@ get_autocommit(dbh) OUTPUT: RETVAL +static int +txn_state(SV* dbh, SV *schema = &PL_sv_undef) + ALIAS: + DBD::SQLite::db::sqlite_txn_state = 1 + CODE: + { + RETVAL = sqlite_db_txn_state(aTHX_ dbh, schema); + } + OUTPUT: + RETVAL + MODULE = DBD::SQLite PACKAGE = DBD::SQLite::st PROTOTYPES: DISABLE diff --git a/dbdimp.c b/dbdimp.c index ef492a7..0165dcb 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -2851,6 +2851,21 @@ sqlite_db_get_autocommit(pTHX_ SV *dbh) return sqlite3_get_autocommit(imp_dbh->db); } +int +sqlite_db_txn_state(pTHX_ SV *dbh, SV *schema) +{ +#if SQLITE_VERSION_NUMBER >= 3034000 + D_imp_dbh(dbh); + if (SvOK(schema) && SvPOK(schema)) { + return sqlite3_txn_state(imp_dbh->db, SvPV_nolen(schema)); + } else { + return sqlite3_txn_state(imp_dbh->db, NULL); + } +#else + return -1; +#endif +} + #include "dbdimp_tokenizer.inc" #include "dbdimp_virtual_table.inc" diff --git a/dbdimp.h b/dbdimp.h index 3f5cc54..04d2b00 100644 --- a/dbdimp.h +++ b/dbdimp.h @@ -137,6 +137,7 @@ int sqlite_db_create_module(pTHX_ SV *dbh, const char *name, const char *perl_cl int sqlite_db_limit(pTHX_ SV *dbh, int id, int new_value); int sqlite_db_config(pTHX_ SV *dbh, int id, int new_value); int sqlite_db_get_autocommit(pTHX_ SV *dbh); +int sqlite_db_txn_state(pTHX_ SV *dbh, SV *schema); int sqlite_db_do_sv(SV *dbh, imp_dbh_t *imp_dbh, SV *sv_statement); void init_cxt(); diff --git a/lib/DBD/SQLite.pm b/lib/DBD/SQLite.pm index 1b6f38c..0ed70e8 100644 --- a/lib/DBD/SQLite.pm +++ b/lib/DBD/SQLite.pm @@ -61,6 +61,7 @@ sub driver { DBD::SQLite::db->install_method('sqlite_limit'); DBD::SQLite::db->install_method('sqlite_db_config'); DBD::SQLite::db->install_method('sqlite_get_autocommit'); + DBD::SQLite::db->install_method('sqlite_txn_state'); $methods_are_installed++; } @@ -2374,6 +2375,14 @@ Returns true if the internal SQLite connection is in an autocommit mode. This does not always return the same value as C<< $dbh->{AutoCommit} >>. This returns false if you explicitly issue a C<> statement. +=head2 $dbh->sqlite_txn_state() + +Returns the internal transaction status of SQLite (not of DBI). +Return values (SQLITE_TXN_NONE, SQLITE_TXN_READ, SQLITE_TXN_WRITE) +can be imported from DBD::SQLite::Constants. You may pass an optional +schema name (usually "main"). If SQLite does not support this function, +or if you pass a wrong schema name, -1 is returned. + =head1 DRIVER FUNCTIONS =head2 DBD::SQLite::compile_options() diff --git a/t/67_txn_state.t b/t/67_txn_state.t new file mode 100644 index 0000000..b4f8c2f --- /dev/null +++ b/t/67_txn_state.t @@ -0,0 +1,41 @@ +use strict; +use warnings; +use lib "t/lib"; +use SQLiteTest qw/connect_ok @CALL_FUNCS/; +use Test::More; +use if -d ".git", "Test::FailWarnings"; +use DBD::SQLite::Constants ':allowed_return_values_from_sqlite3_txn_state'; + +note "test main schema"; +test('main'); +note "test undef schema"; +test(undef); +note "omit schema"; +test(); +done_testing; + +sub test { + my @schema = @_; + die if @schema > 1; + + for my $func (@CALL_FUNCS) { + my $dbh = connect_ok(PrintError => 0, RaiseError => 1); + $dbh->do('create table foo (id)'); + + my $txn_state = $dbh->$func(@schema, 'txn_state'); + is $txn_state => SQLITE_TXN_NONE, "internal transaction is none"; + + $dbh->do('BEGIN'); + + my $row = $dbh->selectrow_arrayref('SELECT * FROM foo'); + + $txn_state = $dbh->$func(@schema, 'txn_state'); + is $txn_state => SQLITE_TXN_READ, "internal transaction is read"; + + $dbh->do('insert into foo values (1)'); + $txn_state = $dbh->$func(@schema, 'txn_state'); + is $txn_state => SQLITE_TXN_WRITE, "internal transaction is write"; + + $dbh->commit; + } +}