# # # patch "app_state.cc" # from [2a1ed84ea7cc9ac7793a92001d4b7f5a28b11587] # to [3a362dd33a8f16581de40e22a6239647b9bad32d] # # patch "app_state.hh" # from [af86dae3f210c378aa1e2f07af9ed544b6fa12c8] # to [e57895ea6314242a40799597824f87686be9d754] # # patch "base.hh" # from [cd23e790e34a3025a6a424f64acd99fa075651fc] # to [a62d857c95d9bc18efcbf5636de75762b6ff02fe] # # patch "database.cc" # from [c1f3a79f013df8595779a3f1f65e20a7f4e0b2ea] # to [98aa81f682d76be89eaa565b9863ede63c863d50] # # patch "database.hh" # from [d52122d8aa928e01819d8f0911e2bec7800d587c] # to [83353b4c402fadb40494abf47ee619453d378284] # # patch "gzip.cc" # from [72e05981fe6cc8aa932363eef6c187241a4bb31d] # to [8bf4654117c605427f39f5b17d958383df18459a] # # patch "key_store.cc" # from [aca28a386622c03aa1e442e0470d67d340f34e14] # to [4bc281f0d80e41b8a2d1ca13708d4aa14f9c1b23] # # patch "key_store.hh" # from [9e813fd91c0bbbcb675c80918094d0817170f868] # to [c26569b00109a15d8df4ceb2f082f90430d069a9] # # patch "m4/botan.m4" # from [5fc9fe115ddccc41d66982627901129ec891ce94] # to [79b58dbd64c54afb9bd328a94556bd798b02a7bf] # # patch "mkstemp.cc" # from [776ee10bb54b88cdba8c3c6b90ce718b575723f2] # to [b5f55d45673507ffbb231f1f3630615b0940d69c] # # patch "monotone.cc" # from [c703b34e55b5245c4aa31fe8202c0514107b7ea3] # to [bd880d127cace25cf1b1d3bbac5064dd0556680f] # # patch "mt_version.cc" # from [1e46c73a8a617ac7db3edd5ee9a8f06a28743046] # to [76772c0f83691ab5bed123dd6c95616904360c52] # # patch "netsync.cc" # from [c200f32af29925de88211de8e7d35c9cac3c9020] # to [c074e2d12991b3ae94ccfd5cc3aa757c4a3b5f8d] # # patch "revision.cc" # from [8d2399e41819f46ed01e60d12c4e884060c30d55] # to [4f11354d1e702a5641e2dc02d34eea871529dde5] # # patch "schema_migration.cc" # from [8ad58d8be2a5a3507f26923363b94a4996e08718] # to [b084f3f873341b23e2622658b2de2a76770f63c7] # ============================================================ --- app_state.cc 2a1ed84ea7cc9ac7793a92001d4b7f5a28b11587 +++ app_state.cc 3a362dd33a8f16581de40e22a6239647b9bad32d @@ -8,10 +8,14 @@ // PURPOSE. #include "base.hh" +#include + +#include + #include "app_state.hh" #include "database.hh" -#include +using boost::shared_ptr; class app_state_private { @@ -20,9 +24,13 @@ app_state::app_state() }; app_state::app_state() - : _hidden(new app_state_private()), lua(this), mtn_automate_allowed(false), - rng(Botan::RandomNumberGenerator::make_rng()) -{} + : _hidden(new app_state_private()), lua(this), mtn_automate_allowed(false) +{ +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + rng = shared_ptr( + Botan::RandomNumberGenerator::make_rng()); +#endif +} app_state::~app_state() {} ============================================================ --- app_state.hh af86dae3f210c378aa1e2f07af9ed544b6fa12c8 +++ app_state.hh e57895ea6314242a40799597824f87686be9d754 @@ -11,7 +11,13 @@ // PURPOSE. #include + +#include +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) #include +#else +#include +#endif #include "options.hh" #include "lua_hooks.hh" @@ -35,7 +41,10 @@ public: options opts; lua_hooks lua; bool mtn_automate_allowed; + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) boost::shared_ptr rng; +#endif }; // Local Variables: ============================================================ --- base.hh cd23e790e34a3025a6a424f64acd99fa075651fc +++ base.hh a62d857c95d9bc18efcbf5636de75762b6ff02fe @@ -20,6 +20,10 @@ #define BOOST_SP_DISABLE_THREADS #define BOOST_MULTI_INDEX_DISABLE_SERIALIZATION +// Undefine this if you do not want to support SQLite versions older +// than 3.3.14. +#define SUPPORT_SQLITE_BEFORE_3003014 + #include #include // it would be nice if there were a @@ -51,9 +55,9 @@ template <> void dump(std::string const #define NORETURN(x) x #endif -// sqlite versions older before 3.3.14 did not have sqlite_prepare_v2. We -// simply fall back to using the old API. -#if SQLITE_VERSION_NUMBER < 3003014 +// SQLite versions before 3.3.14 did not have sqlite_prepare_v2. To support +// those SQLite libraries, we must use the old API. +#ifdef SUPPORT_SQLITE_BEFORE_3003014 #define sqlite3_prepare_v2 sqlite3_prepare #endif ============================================================ --- database.cc c1f3a79f013df8595779a3f1f65e20a7f4e0b2ea +++ database.cc 98aa81f682d76be89eaa565b9863ede63c863d50 @@ -393,9 +393,8 @@ private: query & q); }; -#if SQLITE_VERSION_NUMBER < 3003013 -// sqlite before version 3.3.13 didn't have the hex() function. - +#ifdef SUPPORT_SQLITE_BEFORE_3003014 +// SQLite versions up to and including 3.3.12 didn't have the hex() function void sqlite3_hex_fn(sqlite3_context *f, int nargs, sqlite3_value **args) { @@ -449,8 +448,12 @@ database::database(app_state & app) } database::database(app_state & app) - : lua(app.lua), rng(app.rng) + : lua(app.lua) { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + rng = app.rng; +#endif + boost::shared_ptr & i = app.lookup_db(app.opts.dbname); if (!i) { @@ -2796,9 +2799,16 @@ database::encrypt_rsa(rsa_keypair_id con encryptor(get_pk_encryptor(*pub_key, "EME1(SHA-1)")); SecureVector ct; + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) ct = encryptor->encrypt( reinterpret_cast(plaintext.data()), plaintext.size(), *rng); +#else + ct = encryptor->encrypt( + reinterpret_cast(plaintext.data()), + plaintext.size()); +#endif ciphertext = rsa_oaep_sha_data(string(reinterpret_cast(ct.begin()), ct.size())); } @@ -2919,11 +2929,12 @@ database_impl::install_functions() void database_impl::install_functions() { -#if SQLITE_VERSION_NUMBER < 3003013 - I(sqlite3_create_function(sql(), "hex", -1, - SQLITE_UTF8, NULL, - &sqlite3_hex_fn, - NULL, NULL) == 0); +#ifdef SUPPORT_SQLITE_BEFORE_3003014 + if (sqlite3_libversion_number() < 3003013) + I(sqlite3_create_function(sql(), "hex", -1, + SQLITE_UTF8, NULL, + &sqlite3_hex_fn, + NULL, NULL) == 0); #endif // register any functions we're going to use ============================================================ --- database.hh d52122d8aa928e01819d8f0911e2bec7800d587c +++ database.hh 83353b4c402fadb40494abf47ee619453d378284 @@ -13,7 +13,11 @@ #include "vector.hh" #include #include + +#include +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) #include +#endif #include "rev_types.hh" #include "cert.hh" @@ -437,7 +441,9 @@ private: private: boost::shared_ptr imp; lua_hooks & lua; +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) boost::shared_ptr rng; +#endif }; // not a member function, defined in database_check.cc ============================================================ --- gzip.cc 72e05981fe6cc8aa932363eef6c187241a4bb31d +++ gzip.cc 8bf4654117c605427f39f5b17d958383df18459a @@ -14,9 +14,15 @@ #include #include + +#include + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) #include #include #include +#endif + #include #include #include ============================================================ --- key_store.cc aca28a386622c03aa1e442e0470d67d340f34e14 +++ key_store.cc 4bc281f0d80e41b8a2d1ca13708d4aa14f9c1b23 @@ -51,7 +51,9 @@ struct key_store_state map keys; map hashes; +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) boost::shared_ptr rng; +#endif // These are used to cache keys and signers (if the hook allows). map > privkey_cache; @@ -62,8 +64,12 @@ struct key_store_state key_store_state(app_state & app) : key_dir(app.opts.key_dir), ssh_sign_mode(app.opts.ssh_sign), - have_read(false), lua(app.lua), rng(app.rng) + have_read(false), lua(app.lua) { +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + rng = app.rng; +#endif + N(app.opts.key_dir_given || app.opts.conf_dir_given || !app.opts.no_default_confdir, @@ -159,11 +165,13 @@ key_store::~key_store() key_store::~key_store() {} +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) Botan::RandomNumberGenerator & key_store::get_rng() { return *s->rng; } +#endif system_path const & key_store::get_key_dir() @@ -394,7 +402,11 @@ key_store_state::decrypt_private_key(rsa try // with empty passphrase { Botan::DataSource_Memory ds(kp.priv()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) pkcs8_key.reset(Botan::PKCS8::load_key(ds, *rng, "")); +#else + pkcs8_key.reset(Botan::PKCS8::load_key(ds, "")); +#endif } catch (Botan::Exception & e) { @@ -413,7 +425,11 @@ key_store_state::decrypt_private_key(rsa try { Botan::DataSource_Memory ds(kp.priv()); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) pkcs8_key.reset(Botan::PKCS8::load_key(ds, *rng, phrase())); +#else + pkcs8_key.reset(Botan::PKCS8::load_key(ds, phrase())); +#endif break; } catch (Botan::Exception & e) @@ -486,7 +502,11 @@ key_store::create_key_pair(database & db // okay, now we can create the key P(F("generating key-pair '%s'") % id); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) RSA_PrivateKey priv(*s->rng, static_cast(constants::keylen)); +#else + RSA_PrivateKey priv(static_cast(constants::keylen)); +#endif // serialize and maybe encrypt the private key keypair kp; @@ -494,7 +514,10 @@ key_store::create_key_pair(database & db unfiltered_pipe->start_msg(); if ((*maybe_passphrase)().length()) - Botan::PKCS8::encrypt_key(priv, *unfiltered_pipe, *s->rng, + Botan::PKCS8::encrypt_key(priv, *unfiltered_pipe, +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + *s->rng, +#endif (*maybe_passphrase)(), "PBE-PKCS5v20(SHA-1,TripleDES/CBC)", Botan::RAW_BER); @@ -543,7 +566,11 @@ key_store::change_key_passphrase(rsa_key get_passphrase(new_phrase, id, true, false); unfiltered_pipe->start_msg(); - Botan::PKCS8::encrypt_key(*priv, *unfiltered_pipe, *s->rng, new_phrase(), + Botan::PKCS8::encrypt_key(*priv, *unfiltered_pipe, +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + *s->rng, +#endif + new_phrase(), "PBE-PKCS5v20(SHA-1,TripleDES/CBC)", Botan::RAW_BER); unfiltered_pipe->end_msg(); @@ -658,9 +685,15 @@ key_store::make_signature(database & db, s->signer_cache.insert(make_pair(id, signer)); } +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) sig = signer->sign_message( reinterpret_cast(tosign.data()), tosign.size(), *s->rng); +#else + sig = signer->sign_message( + reinterpret_cast(tosign.data()), + tosign.size()); +#endif sig_string = string(reinterpret_cast(sig.begin()), sig.size()); } @@ -714,7 +747,10 @@ key_store::export_key_for_agent(rsa_keyp p.start_msg(); if (new_phrase().length()) Botan::PKCS8::encrypt_key(*priv, - p, *s->rng, + p, +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + *s->rng, +#endif new_phrase(), "PBE-PKCS5v20(SHA-1,TripleDES/CBC)"); else @@ -727,18 +763,6 @@ key_store::export_key_for_agent(rsa_keyp // Migration from old databases // -#if BOTAN_VERSION_MAJOR == 1 && BOTAN_VERSION_MINOR == 7 && BOTAN_VERSION_PATCH == 14 -// ZZ: ugly hack for botan-1.7.14 which had some API fluctuations -namespace Botan { - Keyed_Filter* get_cipher(const std::string& name, - const SymmetricKey& sk, - Cipher_Dir cd) - { - return get_cipher(global_state(), name, sk, cd); - } -} -#endif - void key_store_state::migrate_old_key_pair (rsa_keypair_id const & id, @@ -775,7 +799,11 @@ key_store_state::migrate_old_key_pair SecureVector arc4_decrypt(arc4_decryptor.read_all()); Botan::DataSource_Memory ds(Botan::PEM_Code::encode(arc4_decrypt, "PRIVATE KEY")); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) pkcs8_key.reset(Botan::PKCS8::load_key(ds, *rng)); +#else + pkcs8_key.reset(Botan::PKCS8::load_key(ds)); +#endif break; } catch (Botan::Exception & e) @@ -797,7 +825,11 @@ key_store_state::migrate_old_key_pair // now we can write out the new key unfiltered_pipe->start_msg(); - Botan::PKCS8::encrypt_key(*priv_key, *unfiltered_pipe, *rng, phrase(), + Botan::PKCS8::encrypt_key(*priv_key, *unfiltered_pipe, +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + *rng, +#endif + phrase(), "PBE-PKCS5v20(SHA-1,TripleDES/CBC)", Botan::RAW_BER); unfiltered_pipe->end_msg(); ============================================================ --- key_store.hh 9e813fd91c0bbbcb675c80918094d0817170f868 +++ key_store.hh c26569b00109a15d8df4ceb2f082f90430d069a9 @@ -2,7 +2,13 @@ #define __KEY_STORE_H__ #include + +#include +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) #include +#else +#include +#endif #include "vector.hh" #include "vocab.hh" @@ -37,7 +43,10 @@ public: explicit key_store(app_state & a); ~key_store(); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) Botan::RandomNumberGenerator & get_rng(); +#endif + system_path const & get_key_dir(); // Basic key I/O ============================================================ --- m4/botan.m4 5fc9fe115ddccc41d66982627901129ec891ce94 +++ m4/botan.m4 79b58dbd64c54afb9bd328a94556bd798b02a7bf @@ -1,4 +1,4 @@ -# Currently we accept botan version 1.7.8 and newer, limited to the +# Currently we accept botan version 1.6.3 and newer, limited to the # development branch 1.7, emitting a warning if the found botan is # newer than 1.7.18. @@ -24,8 +24,12 @@ AC_DEFUN([MTN_FIND_BOTAN], AC_PREPROC_IFELSE([ #include -#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,7,8) +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,6,3) #error "Botan is too old" +#endif + +#if BOTAN_VERSION_CODE == BOTAN_VERSION_CODE_FOR(1,7,14) +#error "Botan 1.7.14 is unusable" #endif], [botan_version_match=yes], [botan_version_match=no]) ============================================================ --- mkstemp.cc 776ee10bb54b88cdba8c3c6b90ce718b575723f2 +++ mkstemp.cc b5f55d45673507ffbb231f1f3630615b0940d69c @@ -17,6 +17,8 @@ #include #include + +#include #include #ifndef O_BINARY @@ -33,8 +35,10 @@ monotone_mkstemp(string &tmpl) int count = 0, fd = -1; string tmp; +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) boost::shared_ptr rng( Botan::RandomNumberGenerator::make_rng()); +#endif static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; @@ -49,7 +53,12 @@ monotone_mkstemp(string &tmpl) tmp = tmpl.substr(0, len-6); for (i = 0; i < 6; ++i) +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) tmp.append(1, letters[rng->next_byte() % NLETTERS]); +#else + tmp.append(1, letters[Botan::Global_RNG::random() % NLETTERS]); +#endif + #ifdef _MSC_VER fd = _open(tmp.c_str(), _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY, 0600); #else ============================================================ --- monotone.cc c703b34e55b5245c4aa31fe8202c0514107b7ea3 +++ monotone.cc bd880d127cace25cf1b1d3bbac5064dd0556680f @@ -16,6 +16,9 @@ #include #include +#include +#include + #include "i18n.h" #include "app_state.hh" #include "botan_pipe_cache.hh" @@ -202,6 +205,39 @@ cpp_main(int argc, char ** argv) I(!ui.prog_name.empty()); } + // check the SQLite library version we got dynamically linked against. +#ifdef SUPPORT_SQLITE_BEFORE_3003014 + N(sqlite3_libversion_number() >= 3003008, + F("This monotone binary requires at least SQLite 3.3.8 to run.")); +#else + N(sqlite3_libversion_number() >= 3003014, + F("This monotone binary requires at least SQLite 3.3.14 to run.")); +#endif + + // check the botan library version we got linked against. +#if BOTAN_VERSION_MAJOR == 1 && BOTAN_VERSION_MINOR == 6 + N(Botan::version_major() == 1 && Botan::version_minor() == 6, + F("This monotone binary requires Botan 1.6.x.")); + +#elif BOTAN_VERSION_MAJOR == 1 && BOTAN_VERSION_MINOR == 7 + N(Botan::version_major() == 1 && Botan::version_minor() == 7, + F("This monotone binary requires Botan 1.7.x.")); + + // Remember that botan 1.7 is a development branch, so its API might + // be changing. However, besides the glitch of 1.7.14, no API changes + // affect monotone. + N(Botan::version_patch() != 14, + F("This monotone binary does not support Botan 1.7.14.")); + +#if BOTAN_VERSION_PATCH < 7 + N(Botan::version_patch() < 7, + F("This monotone binary requires Botan 1.7.6 or before.")); +#else + N(Botan::version_patch() >= 7, + F("This monotone binary requires Botan 1.7.7 or newer.")); +#endif +#endif + app_state app; try { ============================================================ --- mt_version.cc 1e46c73a8a617ac7db3edd5ee9a8f06a28743046 +++ mt_version.cc 76772c0f83691ab5bed123dd6c95616904360c52 @@ -81,20 +81,21 @@ get_full_version(string & out) "C++ compiler : %s\n" "C++ standard library: %s\n" "Boost version : %s\n" - "SQLite version : %s\n" + "SQLite version : %s (compiled against %s)\n" "Lua version : %s\n" "PCRE version : %d.%d\n" - "Botan version : %d.%d.%d\n" + "Botan version : %d.%d.%d (compiled against %d.%d.%d)\n" "Changes since base revision:\n" "%s") % s % BOOST_COMPILER % BOOST_STDLIB % BOOST_LIB_VERSION - % SQLITE_VERSION + % sqlite3_libversion() % SQLITE_VERSION % LUA_RELEASE % PCRE_MAJOR % PCRE_MINOR - % BOTAN_VERSION_MAJOR % BOTAN_VERSION_MINOR % BOTAN_VERSION_PATCH + % Botan::version_major() % Botan::version_minor() % Botan::version_patch() + % BOTAN_VERSION_MAJOR % BOTAN_VERSION_MINOR % BOTAN_VERSION_PATCH % string(package_full_revision_constant); out = oss.str(); } ============================================================ --- netsync.cc c200f32af29925de88211de8e7d35c9cac3c9020 +++ netsync.cc c074e2d12991b3ae94ccfd5cc3aa757c4a3b5f8d @@ -24,6 +24,7 @@ #include #include +#include #include "lua_hooks.hh" #include "key_store.hh" @@ -798,8 +799,14 @@ session::mk_nonce() { I(this->saved_nonce().empty()); char buf[constants::merkle_hash_length_in_bytes]; + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) keys.get_rng().randomize(reinterpret_cast(buf), - constants::merkle_hash_length_in_bytes); + constants::merkle_hash_length_in_bytes); +#else + Botan::Global_RNG::randomize(reinterpret_cast(buf), + constants::merkle_hash_length_in_bytes); +#endif this->saved_nonce = id(string(buf, buf + constants::merkle_hash_length_in_bytes)); I(this->saved_nonce().size() == constants::merkle_hash_length_in_bytes); return this->saved_nonce; ============================================================ --- revision.cc 8d2399e41819f46ed01e60d12c4e884060c30d55 +++ revision.cc 4f11354d1e702a5641e2dc02d34eea871529dde5 @@ -22,6 +22,7 @@ #include #include +#include #include "basic_io.hh" #include "cert.hh" @@ -933,7 +934,13 @@ void anc_graph::write_certs() for (set::const_iterator i = branches.begin(); i != branches.end(); ++i) { char buf[constants::epochlen_bytes]; - keys.get_rng().randomize(reinterpret_cast(buf), constants::epochlen_bytes); +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) + keys.get_rng().randomize(reinterpret_cast(buf), + constants::epochlen_bytes); +#else + Botan::Global_RNG::randomize(reinterpret_cast(buf), + constants::epochlen_bytes); +#endif epoch_data new_epoch(string(buf, buf + constants::epochlen_bytes)); L(FL("setting epoch for %s to %s") % *i % new_epoch); ============================================================ --- schema_migration.cc 8ad58d8be2a5a3507f26923363b94a4996e08718 +++ schema_migration.cc b084f3f873341b23e2622658b2de2a76770f63c7 @@ -1000,8 +1000,8 @@ check_sql_schema(sqlite3 * db, system_pa % filename % ui.prog_name); } -// import the hex function for old sqlite libraries -#if SQLITE_VERSION_NUMBER < 3003013 +#ifdef SUPPORT_SQLITE_BEFORE_3003014 +// import the hex function for old sqlite libraries from database.cc void sqlite3_hex_fn(sqlite3_context *f, int nargs, sqlite3_value **args); #endif @@ -1041,9 +1041,12 @@ migrate_sql_schema(sqlite3 * db, key_sto return; } -#if SQLITE_VERSION_NUMBER < 3003013 - sql::create_function(db, "hex", sqlite3_hex_fn); +#ifdef SUPPORT_SQLITE_BEFORE_3003014 + // SQLite up to and including 3.3.12 didn't have a hex() function + if (sqlite3_libversion_number() <= 3003012) + sql::create_function(db, "hex", sqlite3_hex_fn); #endif + sql::create_function(db, "sha1", sqlite_sha1_fn); sql::create_function(db, "unbase64", sqlite3_unbase64_fn); sql::create_function(db, "unhex", sqlite3_unhex_fn); @@ -1116,9 +1119,12 @@ test_migration_step(sqlite3 * db, key_st { I(db != NULL); -#if SQLITE_VERSION_NUMBER < 3003013 - sql::create_function(db, "hex", sqlite3_hex_fn); +#ifdef SUPPORT_SQLITE_BEFORE_3003014 + // SQLite up to and including 3.3.12 didn't have a hex() function + if (sqlite3_libversion_number() <= 3003012) + sql::create_function(db, "hex", sqlite3_hex_fn); #endif + sql::create_function(db, "sha1", sqlite_sha1_fn); sql::create_function(db, "unbase64", sqlite3_unbase64_fn); sql::create_function(db, "unhex", sqlite3_unhex_fn);