Skip to content

Commit

Permalink
Merge pull request #520 from wjlroe/sqlite-status
Browse files Browse the repository at this point in the history
Add SQLite3.status to call sqlite3_status
  • Loading branch information
flavorjones committed Apr 16, 2024
2 parents 92e5c16 + b14a84e commit 6a2f56c
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This release drops support for Ruby 2.7. [#453] @flavorjones
- Support the `SUPER_JOURNAL` flag which is an alias for `MASTER_JOURNAL` as of sqlite 3.33.0. [#467] @flavorjones
- `Statement#stat` and `Statement#memused` introduced to report statistics. [#461] @fractaledmind
- `Statement#sql` and `Statement#expanded_sql` introduced to retrieve the SQL statement associated with the `Statement` object. [#293, #498] @tenderlove
- `SQLite3.status` introduced to return run-time status and reset high-water marks. See `SQLite3::Constants::Status` for details. [#520] @wjlroe


### Improved
Expand Down
37 changes: 37 additions & 0 deletions ext/sqlite3/sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,42 @@ threadsafe_p(VALUE UNUSED(klass))
return INT2NUM(sqlite3_threadsafe());
}

/*
* call-seq:
* status(parameter) → Hash
* status(parameter, reset_flag = false) → Hash
*
* Queries the SQLite3 library for run-time status information. Passing a truthy +reset_flag+ will
* reset the highwater mark to the current value.
*
* [Parameters]
* - +parameter+ (Integer, SQLite3::Constants::Status): The status parameter to query.
* - +reset_flag+ (Boolean): Whether to reset the highwater mark. (default is +false+)
*
* [Returns]
* A Hash containing +:current+ and +:highwater+ keys for integer values.
*/
static VALUE
rb_sqlite3_status(int argc, VALUE *argv, VALUE klass)
{
VALUE opArg, resetFlagArg;

rb_scan_args(argc, argv, "11", &opArg, &resetFlagArg);

int op = NUM2INT(opArg);
bool resetFlag = RTEST(resetFlagArg);

int pCurrent = 0;
int pHighwater = 0;
sqlite3_status(op, &pCurrent, &pHighwater, resetFlag);

VALUE hash = rb_hash_new();
rb_hash_aset(hash, ID2SYM(rb_intern("current")), INT2FIX(pCurrent));
rb_hash_aset(hash, ID2SYM(rb_intern("highwater")), INT2FIX(pHighwater));

return hash;
}

void
init_sqlite3_constants(void)
{
Expand Down Expand Up @@ -164,6 +200,7 @@ Init_sqlite3_native(void)
rb_define_singleton_method(mSqlite3, "sqlcipher?", using_sqlcipher, 0);
rb_define_singleton_method(mSqlite3, "libversion", libversion, 0);
rb_define_singleton_method(mSqlite3, "threadsafe", threadsafe_p, 0);
rb_define_singleton_method(mSqlite3, "status", rb_sqlite3_status, -1);
rb_define_const(mSqlite3, "SQLITE_VERSION", rb_str_new2(SQLITE_VERSION));
rb_define_const(mSqlite3, "SQLITE_VERSION_NUMBER", INT2FIX(SQLITE_VERSION_NUMBER));
rb_define_const(mSqlite3, "SQLITE_LOADED_VERSION", rb_str_new2(sqlite3_libversion()));
Expand Down
54 changes: 54 additions & 0 deletions lib/sqlite3/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,59 @@ module ErrorCode
# sqlite_step() has finished executing
DONE = 101
end

#
# CAPI3REF: Status Parameters
#
# These integer constants designate various run-time status parameters
# that can be returned by SQLite3.status
#
module Status
# This parameter is the current amount of memory checked out using sqlite3_malloc(), either
# directly or indirectly. The figure includes calls made to sqlite3_malloc() by the
# application and internal memory usage by the SQLite library. Auxiliary page-cache memory
# controlled by SQLITE_CONFIG_PAGECACHE is not included in this parameter. The amount returned
# is the sum of the allocation sizes as reported by the xSize method in sqlite3_mem_methods.
MEMORY_USED = 0

# This parameter returns the number of pages used out of the pagecache memory allocator that
# was configured using SQLITE_CONFIG_PAGECACHE. The value returned is in pages, not in bytes.
PAGECACHE_USED = 1

# This parameter returns the number of bytes of page cache allocation which could not be
# satisfied by the SQLITE_CONFIG_PAGECACHE buffer and where forced to overflow to
# sqlite3_malloc(). The returned value includes allocations that overflowed because they where
# too large (they were larger than the "sz" parameter to SQLITE_CONFIG_PAGECACHE) and
# allocations that overflowed because no space was left in the page cache.
PAGECACHE_OVERFLOW = 2

# NOT USED
SCRATCH_USED = 3

# NOT USED
SCRATCH_OVERFLOW = 4

# This parameter records the largest memory allocation request handed to sqlite3_malloc() or
# sqlite3_realloc() (or their internal equivalents). Only the value returned in the
# *pHighwater parameter to sqlite3_status() is of interest. The value written into the
# *pCurrent parameter is undefined.
MALLOC_SIZE = 5

# The *pHighwater parameter records the deepest parser stack. The *pCurrent value is
# undefined. The *pHighwater value is only meaningful if SQLite is compiled with
# YYTRACKMAXSTACKDEPTH.
PARSER_STACK = 6

# This parameter records the largest memory allocation request handed to the pagecache memory
# allocator. Only the value returned in the *pHighwater parameter to sqlite3_status() is of
# interest. The value written into the *pCurrent parameter is undefined.
PAGECACHE_SIZE = 7

# NOT USED
SCRATCH_SIZE = 8

# This parameter records the number of separate memory allocations currently checked out.
MALLOC_COUNT = 9
end
end
end
16 changes: 16 additions & 0 deletions test/test_sqlite3.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,21 @@ def test_threadsafe?
def test_compiled_version_and_loaded_version
assert_equal(SQLite3::SQLITE_VERSION, SQLite3::SQLITE_LOADED_VERSION)
end

def test_status
status = SQLite3.status(SQLite3::Constants::Status::MEMORY_USED)
assert_operator(status.fetch(:current), :>=, 0)
assert_operator(status.fetch(:highwater), :>=, status.fetch(:current))
end

def test_status_reset_highwater_mark
status = SQLite3.status(SQLite3::Constants::Status::MEMORY_USED, false)
assert_operator(status.fetch(:current), :>=, 0)
assert_operator(status.fetch(:highwater), :>=, status.fetch(:current))

status = SQLite3.status(SQLite3::Constants::Status::MEMORY_USED, true)
assert_operator(status.fetch(:current), :>=, 0)
assert_operator(status.fetch(:highwater), :>=, status.fetch(:current))
end
end
end

0 comments on commit 6a2f56c

Please sign in to comment.