From ac73b3ec7ffe168337f91abbfea54fdf7097e01b Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Fri, 7 Sep 2012 19:35:52 +0000 Subject: [PATCH] implemented status interfaces --- SQLite.xs | 29 +++++++++++++++++ dbdimp.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++ dbdimp.h | 3 ++ lib/DBD/SQLite.pm | 26 ++++++++++++++++ t/53_status.t | 53 +++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+) create mode 100644 t/53_status.t diff --git a/SQLite.xs b/SQLite.xs index 23c8c48..d6c72d1 100644 --- a/SQLite.xs +++ b/SQLite.xs @@ -257,12 +257,33 @@ register_fts3_perl_tokenizer(dbh) OUTPUT: RETVAL +HV* +db_status(dbh, reset = 0) + SV* dbh + int reset + ALIAS: + DBD::SQLite::db::sqlite_db_status = 1 + CODE: + RETVAL = (HV*)_sqlite_db_status(aTHX_ dbh, reset); + OUTPUT: + RETVAL MODULE = DBD::SQLite PACKAGE = DBD::SQLite::st PROTOTYPES: DISABLE +HV* +st_status(sth, reset = 0) + SV* sth + int reset + ALIAS: + DBD::SQLite::st::sqlite_st_status = 1 + CODE: + RETVAL = (HV*)_sqlite_st_status(aTHX_ sth, reset); + OUTPUT: + RETVAL + MODULE = DBD::SQLite PACKAGE = DBD::SQLite # a couple of constants exported from sqlite3.h @@ -284,6 +305,14 @@ compile_options() } XSRETURN(n); +HV* +sqlite_status(reset = 0) + int reset + CODE: + RETVAL = (HV*)_sqlite_status(reset); + OUTPUT: + RETVAL + static int OK() CODE: diff --git a/dbdimp.c b/dbdimp.c index 9b50c79..5a009a7 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -1240,6 +1240,85 @@ sqlite_compile_options() return (AV*)sv_2mortal((SV*)av); } +#define _stores_status(op, key) \ + if (sqlite3_status(op, &cur, &hi, reset) == SQLITE_OK) { \ + anon = (HV*)sv_2mortal((SV*)newHV()); \ + hv_stores(anon, "current", newSViv(cur)); \ + hv_stores(anon, "highwater", newSViv(hi)); \ + hv_stores(hv, key, newRV_inc((SV*)anon)); \ + } + +#define _stores_dbstatus(op, key) \ + if (sqlite3_db_status(imp_dbh->db, op, &cur, &hi, reset) == SQLITE_OK) { \ + anon = (HV*)sv_2mortal((SV*)newHV()); \ + hv_stores(anon, "current", newSViv(cur)); \ + hv_stores(anon, "highwater", newSViv(hi)); \ + hv_stores(hv, key, newRV_inc((SV*)anon)); \ + } + +#define _stores_ststatus(op, key) \ + hv_stores(hv, key, newSViv(sqlite3_stmt_status(imp_sth->stmt, op, reset))) + +HV * +_sqlite_status(int reset) +{ + dTHX; + int cur, hi; + HV *hv = (HV*)sv_2mortal((SV*)newHV()); + HV *anon; + + _stores_status(SQLITE_STATUS_MEMORY_USED, "memory_used"); + _stores_status(SQLITE_STATUS_PAGECACHE_USED, "pagecache_used"); + _stores_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, "pagecache_overflow"); + _stores_status(SQLITE_STATUS_SCRATCH_USED, "scratch_used"); + + _stores_status(SQLITE_STATUS_SCRATCH_OVERFLOW, "scratch_overflow"); + + _stores_status(SQLITE_STATUS_MALLOC_SIZE, "malloc_size"); + _stores_status(SQLITE_STATUS_PARSER_STACK, "parser_stack"); + _stores_status(SQLITE_STATUS_PAGECACHE_SIZE, "pagecache_size"); + _stores_status(SQLITE_STATUS_SCRATCH_SIZE, "scratch_size"); + _stores_status(SQLITE_STATUS_MALLOC_COUNT, "malloc_count"); + _stores_status(SQLITE_STATUS_SCRATCH_OVERFLOW, "scratch_overflow"); + + return hv; +} + +HV * +_sqlite_db_status(pTHX_ SV* dbh, int reset) +{ + D_imp_dbh(dbh); + int cur, hi; + HV *hv = (HV*)sv_2mortal((SV*)newHV()); + HV *anon; + + _stores_dbstatus(SQLITE_DBSTATUS_LOOKASIDE_USED, "lookaside_used"); + _stores_dbstatus(SQLITE_DBSTATUS_CACHE_USED, "cache_used"); + _stores_dbstatus(SQLITE_DBSTATUS_SCHEMA_USED, "schema_used"); + _stores_dbstatus(SQLITE_DBSTATUS_STMT_USED, "stmt_used"); + _stores_dbstatus(SQLITE_DBSTATUS_LOOKASIDE_HIT, "lookaside_hit"); + _stores_dbstatus(SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, "lookaside_miss_size"); + _stores_dbstatus(SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, "lookaside_miss_full"); + _stores_dbstatus(SQLITE_DBSTATUS_CACHE_HIT, "cache_hit"); + _stores_dbstatus(SQLITE_DBSTATUS_CACHE_MISS, "cache_miss"); + _stores_dbstatus(SQLITE_DBSTATUS_CACHE_WRITE, "cache_write"); + + return hv; +} + +HV * +_sqlite_st_status(pTHX_ SV* sth, int reset) +{ + D_imp_sth(sth); + HV *hv = (HV*)sv_2mortal((SV*)newHV()); + + _stores_ststatus(SQLITE_STMTSTATUS_FULLSCAN_STEP, "fullscan_step"); + _stores_ststatus(SQLITE_STMTSTATUS_SORT, "sort"); + _stores_ststatus(SQLITE_STMTSTATUS_AUTOINDEX, "autoindex"); + + return hv; +} + SV * sqlite_db_filename(pTHX_ SV *dbh) { diff --git a/dbdimp.h b/dbdimp.h index a5898a8..762a4bd 100644 --- a/dbdimp.h +++ b/dbdimp.h @@ -107,9 +107,12 @@ AV* sqlite_compile_options(); int sqlite_db_trace(pTHX_ SV *dbh, SV *func); int sqlite_db_profile(pTHX_ SV *dbh, SV *func); HV* sqlite_db_table_column_metadata(pTHX_ SV *dbh, SV *dbname, SV *tablename, SV *columnname); +HV* sqlite_db_status(pTHX_ SV *dbh, int reset); SV* sqlite_db_filename(pTHX_ SV *dbh); int sqlite_db_register_fts3_perl_tokenizer(pTHX_ SV *dbh); +HV* sqlite_status(int reset); +HV* sqlite_st_status(pTHX_ SV *sth, imp_sth_t *imp_sth, int reset); #ifdef SvUTF8_on diff --git a/lib/DBD/SQLite.pm b/lib/DBD/SQLite.pm index dcbab34..50dace0 100644 --- a/lib/DBD/SQLite.pm +++ b/lib/DBD/SQLite.pm @@ -53,6 +53,9 @@ sub driver { DBD::SQLite::db->install_method('sqlite_profile', { O => 0x0004 }); DBD::SQLite::db->install_method('sqlite_table_column_metadata', { O => 0x0004 }); DBD::SQLite::db->install_method('sqlite_db_filename', { O => 0x0004 }); + DBD::SQLite::db->install_method('sqlite_db_status', { O => 0x0004 }); + + DBD::SQLite::st->install_method('sqlite_st_status', { O => 0x0004 }); $methods_are_installed++; } @@ -1782,6 +1785,29 @@ Returns an array of compile options (available since sqlite 3.6.23, bundled in DBD::SQLite 1.30_01), or an empty array if the bundled library is old or compiled with SQLITE_OMIT_COMPILEOPTION_DIAGS. +=head2 DBD::SQLite::sqlite_status() + +Returns a hash reference that holds a set of status information of SQLite runtime such as memory usage or page cache usage (see L for details). Each of the entry contains the current value and the highwater value. + + my $status = DBD::SQLite::sqlite_status(); + my $cur = $status->{memory_used}{current}; + my $high = $status->{memory_used}{highwater}; + +You may also pass 0 as an argument to reset the status. + +=head2 $dbh->sqlite_db_status() + +Returns a hash reference that holds a set of status information of database connection such as cache usage. See L for details. You may also pass 0 as an argument to reset the status. + +=head2 $sth->sqlite_st_status() + +Returns a hash reference that holds a set of status information of SQLite statement handle such as full table scan count. See L for details. Statement status only holds the current value. + + my $status = $sth->sqlite_st_status(); + my $cur = $status->{fullscan_step}; + +You may also pass 0 as an argument to reset the status. + =head1 DRIVER CONSTANTS A subset of SQLite C constants are made available to Perl, diff --git a/t/53_status.t b/t/53_status.t new file mode 100644 index 0000000..50b29e0 --- /dev/null +++ b/t/53_status.t @@ -0,0 +1,53 @@ +#!/usr/bin/perl + +use strict; +BEGIN { + $| = 1; + $^W = 1; +} + +use t::lib::Test qw/connect_ok @CALL_FUNCS/; +use Test::More; +#use Test::NoWarnings; + +#plan tests => 6 * @CALL_FUNCS + 1; + +my $dbh = connect_ok(); +{ + $dbh->do('create table foo (id integer primary key, text)'); + my $sth = $dbh->prepare('insert into foo values(?, ?)'); + $sth->execute($_, "text$_") for 1..100; +} + +{ + my $status = DBD::SQLite::sqlite_status(); + ok $status && ref $status eq ref {}, "status is a hashref"; + my $num_of_keys = scalar keys %$status; + ok $num_of_keys, "status: $num_of_keys indicators"; + my $used_mem = $status->{memory_used}{current}; + ok defined $used_mem && $used_mem, "current used memory: $used_mem"; +} + +for my $func (@CALL_FUNCS) { + { + my $db_status = $dbh->$func('db_status'); + ok $db_status && ref $db_status eq ref {}, "db status is a hashref"; + my $num_of_keys = scalar keys %$db_status; + ok $num_of_keys, "db status: $num_of_keys indicators"; + my $used_cache = $db_status->{cache_used}{current}; + ok defined $used_cache && $used_cache, "current used cache: $used_cache"; + } + + { + my $sth = $dbh->prepare('select * from foo where text = ? order by text desc'); + $sth->execute("text1"); + my $st_status = $sth->$func('st_status'); + ok $st_status && ref $st_status eq ref {}, "st status is a hashref"; + my $num_of_keys = scalar keys %$st_status; + ok $num_of_keys, "st status: $num_of_keys indicators"; + my $sort = $st_status->{sort}; + ok defined $sort && $sort, "num of sort: $sort"; + } +} + +done_testing;