diff --git a/CHANGELOG.md b/CHANGELOG.md index 930a82fc..3177ef82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # sqlite3-ruby Changelog +## next / unreleased + +### Added + +- `Database#optimize` which wraps the `pragma optimize;` statement. Also added `Constants::Optimize` to allow advanced users to pass a bitmask of options. See https://www.sqlite.org/pragma.html#pragma_optimize. [#572] @alexcwatt @flavorjones + + ## 2.2.0 / 2024-10-30 ### Added diff --git a/lib/sqlite3/constants.rb b/lib/sqlite3/constants.rb index 77e82e19..eae77b7c 100644 --- a/lib/sqlite3/constants.rb +++ b/lib/sqlite3/constants.rb @@ -170,5 +170,29 @@ module Status # This parameter records the number of separate memory allocations currently checked out. MALLOC_COUNT = 9 end + + module Optimize + # Debugging mode. Do not actually perform any optimizations but instead return one line of + # text for each optimization that would have been done. Off by default. + DEBUG = 0x00001 + + # Run ANALYZE on tables that might benefit. On by default. + ANALYZE_TABLES = 0x00002 + + # When running ANALYZE, set a temporary PRAGMA analysis_limit to prevent excess run-time. On + # by default. + LIMIT_ANALYZE = 0x00010 + + # Check the size of all tables, not just tables that have not been recently used, to see if + # any have grown and shrunk significantly and hence might benefit from being re-analyzed. Off + # by default. + CHECK_ALL_TABLES = 0x10000 + + # Useful for adding a bit to the default behavior, for example + # + # db.optimize(Optimize::DEFAULT | Optimize::CHECK_ALL_TABLES) + # + DEFAULT = ANALYZE_TABLES | LIMIT_ANALYZE + end end end diff --git a/lib/sqlite3/pragmas.rb b/lib/sqlite3/pragmas.rb index 40ff4312..08ad037b 100644 --- a/lib/sqlite3/pragmas.rb +++ b/lib/sqlite3/pragmas.rb @@ -338,6 +338,20 @@ def mmap_size=(size) set_int_pragma "mmap_size", size end + # Attempt to optimize the database. + # + # To customize the optimization options, pass +bitmask+ with a combination + # of the Constants::Optimize masks. + # + # See https://www.sqlite.org/pragma.html#pragma_optimize for more information. + def optimize(bitmask = nil) + if bitmask + set_int_pragma "optimize", bitmask + else + execute("PRAGMA optimize") + end + end + def page_count get_int_pragma "page_count" end diff --git a/test/test_pragmas.rb b/test/test_pragmas.rb index d09a78c5..4778ad00 100644 --- a/test/test_pragmas.rb +++ b/test/test_pragmas.rb @@ -2,9 +2,27 @@ module SQLite3 class TestPragmas < SQLite3::TestCase + class DatabaseTracker < SQLite3::Database + attr_reader :test_statements + + def initialize(...) + @test_statements = [] + super + end + + def execute(sql, bind_vars = [], &block) + @test_statements << sql + super + end + end + def setup super - @db = SQLite3::Database.new(":memory:") + @db = DatabaseTracker.new(":memory:") + end + + def teardown + @db.close end def test_pragma_errors @@ -32,5 +50,28 @@ def test_set_boolean_pragma ensure @db.set_boolean_pragma("read_uncommitted", 0) end + + def test_optimize_with_no_args + @db.optimize + + assert_equal(["PRAGMA optimize"], @db.test_statements) + end + + def test_optimize_with_args + @db.optimize(Constants::Optimize::DEFAULT) + @db.optimize(Constants::Optimize::ANALYZE_TABLES | Constants::Optimize::LIMIT_ANALYZE) + @db.optimize(Constants::Optimize::ANALYZE_TABLES | Constants::Optimize::DEBUG) + @db.optimize(Constants::Optimize::DEFAULT | Constants::Optimize::CHECK_ALL_TABLES) + + assert_equal( + [ + "PRAGMA optimize=18", + "PRAGMA optimize=18", + "PRAGMA optimize=3", + "PRAGMA optimize=65554" + ], + @db.test_statements + ) + end end end