Skip to content

Commit 6a2f56c

Browse files
authored
Merge pull request #520 from wjlroe/sqlite-status
Add SQLite3.status to call sqlite3_status
2 parents 92e5c16 + b14a84e commit 6a2f56c

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ This release drops support for Ruby 2.7. [#453] @flavorjones
1515
- Support the `SUPER_JOURNAL` flag which is an alias for `MASTER_JOURNAL` as of sqlite 3.33.0. [#467] @flavorjones
1616
- `Statement#stat` and `Statement#memused` introduced to report statistics. [#461] @fractaledmind
1717
- `Statement#sql` and `Statement#expanded_sql` introduced to retrieve the SQL statement associated with the `Statement` object. [#293, #498] @tenderlove
18+
- `SQLite3.status` introduced to return run-time status and reset high-water marks. See `SQLite3::Constants::Status` for details. [#520] @wjlroe
1819

1920

2021
### Improved

ext/sqlite3/sqlite3.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,42 @@ threadsafe_p(VALUE UNUSED(klass))
8585
return INT2NUM(sqlite3_threadsafe());
8686
}
8787

88+
/*
89+
* call-seq:
90+
* status(parameter) → Hash
91+
* status(parameter, reset_flag = false) → Hash
92+
*
93+
* Queries the SQLite3 library for run-time status information. Passing a truthy +reset_flag+ will
94+
* reset the highwater mark to the current value.
95+
*
96+
* [Parameters]
97+
* - +parameter+ (Integer, SQLite3::Constants::Status): The status parameter to query.
98+
* - +reset_flag+ (Boolean): Whether to reset the highwater mark. (default is +false+)
99+
*
100+
* [Returns]
101+
* A Hash containing +:current+ and +:highwater+ keys for integer values.
102+
*/
103+
static VALUE
104+
rb_sqlite3_status(int argc, VALUE *argv, VALUE klass)
105+
{
106+
VALUE opArg, resetFlagArg;
107+
108+
rb_scan_args(argc, argv, "11", &opArg, &resetFlagArg);
109+
110+
int op = NUM2INT(opArg);
111+
bool resetFlag = RTEST(resetFlagArg);
112+
113+
int pCurrent = 0;
114+
int pHighwater = 0;
115+
sqlite3_status(op, &pCurrent, &pHighwater, resetFlag);
116+
117+
VALUE hash = rb_hash_new();
118+
rb_hash_aset(hash, ID2SYM(rb_intern("current")), INT2FIX(pCurrent));
119+
rb_hash_aset(hash, ID2SYM(rb_intern("highwater")), INT2FIX(pHighwater));
120+
121+
return hash;
122+
}
123+
88124
void
89125
init_sqlite3_constants(void)
90126
{
@@ -164,6 +200,7 @@ Init_sqlite3_native(void)
164200
rb_define_singleton_method(mSqlite3, "sqlcipher?", using_sqlcipher, 0);
165201
rb_define_singleton_method(mSqlite3, "libversion", libversion, 0);
166202
rb_define_singleton_method(mSqlite3, "threadsafe", threadsafe_p, 0);
203+
rb_define_singleton_method(mSqlite3, "status", rb_sqlite3_status, -1);
167204
rb_define_const(mSqlite3, "SQLITE_VERSION", rb_str_new2(SQLITE_VERSION));
168205
rb_define_const(mSqlite3, "SQLITE_VERSION_NUMBER", INT2FIX(SQLITE_VERSION_NUMBER));
169206
rb_define_const(mSqlite3, "SQLITE_LOADED_VERSION", rb_str_new2(sqlite3_libversion()));

lib/sqlite3/constants.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,59 @@ module ErrorCode
116116
# sqlite_step() has finished executing
117117
DONE = 101
118118
end
119+
120+
#
121+
# CAPI3REF: Status Parameters
122+
#
123+
# These integer constants designate various run-time status parameters
124+
# that can be returned by SQLite3.status
125+
#
126+
module Status
127+
# This parameter is the current amount of memory checked out using sqlite3_malloc(), either
128+
# directly or indirectly. The figure includes calls made to sqlite3_malloc() by the
129+
# application and internal memory usage by the SQLite library. Auxiliary page-cache memory
130+
# controlled by SQLITE_CONFIG_PAGECACHE is not included in this parameter. The amount returned
131+
# is the sum of the allocation sizes as reported by the xSize method in sqlite3_mem_methods.
132+
MEMORY_USED = 0
133+
134+
# This parameter returns the number of pages used out of the pagecache memory allocator that
135+
# was configured using SQLITE_CONFIG_PAGECACHE. The value returned is in pages, not in bytes.
136+
PAGECACHE_USED = 1
137+
138+
# This parameter returns the number of bytes of page cache allocation which could not be
139+
# satisfied by the SQLITE_CONFIG_PAGECACHE buffer and where forced to overflow to
140+
# sqlite3_malloc(). The returned value includes allocations that overflowed because they where
141+
# too large (they were larger than the "sz" parameter to SQLITE_CONFIG_PAGECACHE) and
142+
# allocations that overflowed because no space was left in the page cache.
143+
PAGECACHE_OVERFLOW = 2
144+
145+
# NOT USED
146+
SCRATCH_USED = 3
147+
148+
# NOT USED
149+
SCRATCH_OVERFLOW = 4
150+
151+
# This parameter records the largest memory allocation request handed to sqlite3_malloc() or
152+
# sqlite3_realloc() (or their internal equivalents). Only the value returned in the
153+
# *pHighwater parameter to sqlite3_status() is of interest. The value written into the
154+
# *pCurrent parameter is undefined.
155+
MALLOC_SIZE = 5
156+
157+
# The *pHighwater parameter records the deepest parser stack. The *pCurrent value is
158+
# undefined. The *pHighwater value is only meaningful if SQLite is compiled with
159+
# YYTRACKMAXSTACKDEPTH.
160+
PARSER_STACK = 6
161+
162+
# This parameter records the largest memory allocation request handed to the pagecache memory
163+
# allocator. Only the value returned in the *pHighwater parameter to sqlite3_status() is of
164+
# interest. The value written into the *pCurrent parameter is undefined.
165+
PAGECACHE_SIZE = 7
166+
167+
# NOT USED
168+
SCRATCH_SIZE = 8
169+
170+
# This parameter records the number of separate memory allocations currently checked out.
171+
MALLOC_COUNT = 9
172+
end
119173
end
120174
end

test/test_sqlite3.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,21 @@ def test_threadsafe?
2121
def test_compiled_version_and_loaded_version
2222
assert_equal(SQLite3::SQLITE_VERSION, SQLite3::SQLITE_LOADED_VERSION)
2323
end
24+
25+
def test_status
26+
status = SQLite3.status(SQLite3::Constants::Status::MEMORY_USED)
27+
assert_operator(status.fetch(:current), :>=, 0)
28+
assert_operator(status.fetch(:highwater), :>=, status.fetch(:current))
29+
end
30+
31+
def test_status_reset_highwater_mark
32+
status = SQLite3.status(SQLite3::Constants::Status::MEMORY_USED, false)
33+
assert_operator(status.fetch(:current), :>=, 0)
34+
assert_operator(status.fetch(:highwater), :>=, status.fetch(:current))
35+
36+
status = SQLite3.status(SQLite3::Constants::Status::MEMORY_USED, true)
37+
assert_operator(status.fetch(:current), :>=, 0)
38+
assert_operator(status.fetch(:highwater), :>=, status.fetch(:current))
39+
end
2440
end
2541
end

0 commit comments

Comments
 (0)