From c394e33a7a2622de01377a9a55ad3a1475dbd891 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 10 Mar 2016 06:45:19 -0800 Subject: [PATCH 01/10] Add support for building with the various sanitizers When building with ASan, core is also built with ASan enabled (and thus using a local build is required). The other two sanitizers aren't also forwarded on to core's settings since they don't need to be. --- CMake/RealmCore.cmake | 8 ++++++-- CMake/Sanitizers.cmake | 20 ++++++++++++++++++++ CMakeLists.txt | 1 + README.md | 8 ++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 CMake/Sanitizers.cmake diff --git a/CMake/RealmCore.cmake b/CMake/RealmCore.cmake index 76072544..90256b98 100644 --- a/CMake/RealmCore.cmake +++ b/CMake/RealmCore.cmake @@ -4,6 +4,10 @@ if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") set(MAKE_EQUAL_MAKE "MAKE=$(MAKE)") endif() +if(SANITIZE_ADDRESS) + set(MAKEFLAGS "MAKEFLAGS=EXTRA_CFLAGS=-fsanitize=address EXTRA_LDFLAGS=-fsanitize=address") +endif() + if (${CMAKE_VERSION} VERSION_GREATER "3.4.0") set(USES_TERMINAL_BUILD USES_TERMINAL_BUILD 1) endif() @@ -91,7 +95,7 @@ function(clone_and_build_realm_core branch) PREFIX ${core_prefix_directory} BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" - BUILD_COMMAND ${MAKE_EQUAL_MAKE} sh build.sh build + BUILD_COMMAND export ${MAKEFLAGS} && ${MAKE_EQUAL_MAKE} sh build.sh build INSTALL_COMMAND "" ${USES_TERMINAL_BUILD} ) @@ -109,7 +113,7 @@ function(build_existing_realm_core core_directory) BUILD_IN_SOURCE 1 BUILD_ALWAYS 1 CONFIGURE_COMMAND "" - BUILD_COMMAND ${MAKE_EQUAL_MAKE} sh build.sh build + BUILD_COMMAND export ${MAKEFLAGS} && ${MAKE_EQUAL_MAKE} sh build.sh build INSTALL_COMMAND "" ${USES_TERMINAL_BUILD} ) diff --git a/CMake/Sanitizers.cmake b/CMake/Sanitizers.cmake new file mode 100644 index 00000000..202f1a68 --- /dev/null +++ b/CMake/Sanitizers.cmake @@ -0,0 +1,20 @@ +option(SANITIZE_ADDRESS "build with ASan") +option(SANITIZE_THREAD "build with TSan") +option(SANITIZE_UNDEFINED "build with UBSan") + +if(SANITIZE_ADDRESS) + set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=address") +endif() + +if(SANITIZE_THREAD) + set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=thread") +endif() + +if(SANITIZE_UNDEFINED) + set(SANITIZER_FLAGS "${SANITIZER_FLAGS} -fsanitize=undefined") +endif() + +if(SANITIZE_ADDRESS OR SANITIZE_THREAD OR SANITIZE_UNDEFINED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAGS} -fno-omit-frame-pointer") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAGS}") +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d75308f..dabfbc4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ cmake_minimum_required(VERSION 3.2.0) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") include(CompilerFlags) +include(Sanitizers) include(RealmCore) set(REALM_CORE_VERSION "0.97.0" CACHE STRING "") diff --git a/README.md b/README.md index 6776d5a5..70c11003 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,14 @@ cmake -DREALM_CORE_VERSION=/path/to/realm-core The given core tree will be built as part of the object store build. +### Building with Sanitizers + +The object store can be built using ASan, TSan and/or UBSan by specifying `-DSANITIZE_ADDRESS=1`, `-DSANITIZE_THREAD=1`, or `-DSANITIZE_UNDEFINED=1` when inoking CMake. +Building with ASan requires specifying a path to core with `-DREAM_CORE_VERSION` as core needs to also be built with ASan enabled. + +On OS X, the Xcode-provided copy of Clang only comes with ASan, and using TSan or UBSan requires a custom build of Clang. +If you have installed Clang as an external Xcode toolchain (using the `install-xcode-toolchain` when building LLVM), note that you'll have to specify `-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++` when running `cmake` to stop cmake from being too clever. + ## Testing ``` From 991c25865a5edf1ae1337af83482a8f3910fb90e Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Mon, 23 Nov 2015 19:00:31 -0800 Subject: [PATCH 02/10] fix for reload in example --- src/shared_realm.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shared_realm.cpp b/src/shared_realm.cpp index a2c8a2a5..2624f764 100644 --- a/src/shared_realm.cpp +++ b/src/shared_realm.cpp @@ -440,8 +440,6 @@ uint64_t Realm::get_schema_version(const realm::Realm::Config &config) void Realm::close() { - invalidate(); - if (m_coordinator) { m_coordinator->unregister_realm(this); } From 48d8b6a2e71da16b974762c82d3e3769c64f4e1e Mon Sep 17 00:00:00 2001 From: Nabil Hachicha Date: Mon, 14 Mar 2016 16:09:22 -0700 Subject: [PATCH 03/10] fixes #329 --- src/shared_realm.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared_realm.cpp b/src/shared_realm.cpp index 2624f764..b02c954d 100644 --- a/src/shared_realm.cpp +++ b/src/shared_realm.cpp @@ -184,7 +184,8 @@ Group *Realm::read_group() SharedRealm Realm::get_shared_realm(Config config) { - return RealmCoordinator::get_coordinator(config.path)->get_realm(std::move(config)); + auto coordinator = RealmCoordinator::get_coordinator(config.path); + return coordinator->get_realm(std::move(config)); } void Realm::update_schema(std::unique_ptr schema, uint64_t version) From f186c3d1b774635075a294d6c15661c18934d03a Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 18 Mar 2016 19:58:45 -0700 Subject: [PATCH 04/10] android fixes for latests object store --- src/impl/generic/external_commit_helper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impl/generic/external_commit_helper.hpp b/src/impl/generic/external_commit_helper.hpp index cc7fe5eb..8bfe43f2 100644 --- a/src/impl/generic/external_commit_helper.hpp +++ b/src/impl/generic/external_commit_helper.hpp @@ -21,7 +21,7 @@ #include namespace realm { -class ClientHistory; +class Replication; namespace _impl { class RealmCoordinator; @@ -38,7 +38,7 @@ private: RealmCoordinator& m_parent; // A shared group used to listen for changes - std::unique_ptr m_history; + std::unique_ptr m_history; SharedGroup m_sg; // The listener thread From 7ef25e9e143f85fbbb1d896fdca06cd525afb200 Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 18 Mar 2016 20:04:30 -0700 Subject: [PATCH 05/10] its a struct --- src/object_schema.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object_schema.hpp b/src/object_schema.hpp index 4ab2abf1..10a2e555 100644 --- a/src/object_schema.hpp +++ b/src/object_schema.hpp @@ -26,7 +26,7 @@ namespace realm { class Group; - class Property; + struct Property; class ObjectSchema { public: From c32dff40a2db9b6c48d47a0b0070115e59351b8d Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Tue, 1 Mar 2016 17:33:48 -0800 Subject: [PATCH 06/10] case insensitive searches --- src/parser/parser.cpp | 19 ++++++++++---- src/parser/parser.hpp | 7 ++++++ src/parser/query_builder.cpp | 48 ++++++++++++++++++------------------ tests/query.json | 8 +++--- 4 files changed, 49 insertions(+), 33 deletions(-) diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index a16000ee..6819a954 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -66,8 +66,9 @@ struct argument : seq< one< '$' >, must< argument_index > > {}; // expressions and operators struct expr : sor< dq_string, sq_string, number, argument, true_value, false_value, key_path > {}; +struct case_insensitive : pegtl_istring_t("[c]"){}; -struct eq : sor< two< '=' >, one< '=' > > {}; +struct eq : seq< sor< two< '=' >, one< '=' > >, opt< case_insensitive > >{}; struct noteq : pegtl::string< '!', '=' > {}; struct lteq : pegtl::string< '<', '=' > {}; struct lt : one< '<' > {}; @@ -80,7 +81,7 @@ struct ends : pegtl_istring_t("endswith") {}; template struct pad_plus : seq< plus< B >, A, plus< B > > {}; -struct padded_oper : pad_plus< sor< contains, begins, ends >, blank > {}; +struct padded_oper : pad_plus< seq< sor< contains, begins, ends>, opt< case_insensitive > >, blank > {}; struct symbolic_oper : pad< sor< eq, noteq, lteq, lt, gteq, gt >, blank > {}; // predicates @@ -236,8 +237,7 @@ EXPRESSION_ACTION(number, Expression::Type::Number) EXPRESSION_ACTION(true_value, Expression::Type::True) EXPRESSION_ACTION(false_value, Expression::Type::False) EXPRESSION_ACTION(argument_index, Expression::Type::Argument) - - + template<> struct action< true_pred > { static void apply( const input & in, ParserState & state ) @@ -271,7 +271,16 @@ OPERATOR_ACTION(lt, Predicate::Operator::LessThan) OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith) OPERATOR_ACTION(ends, Predicate::Operator::EndsWith) OPERATOR_ACTION(contains, Predicate::Operator::Contains) - + +template<> struct action< case_insensitive > +{ + static void apply( const input & in, ParserState & state ) + { + DEBUG_PRINT_TOKEN(in.string()); + state.last_predicate()->cmpr.option = Predicate::OperatorOption::CaseInsensitive; + } +}; + template<> struct action< one< '(' > > { static void apply( const input & in, ParserState & state ) diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index 21143538..2f2ebed2 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -57,10 +57,17 @@ struct Predicate EndsWith, Contains }; + + enum class OperatorOption + { + None, + CaseInsensitive, + }; struct Comparison { Operator op = Operator::None; + OperatorOption option = OperatorOption::None; Expression expr[2] = {{Expression::Type::None, ""}, {Expression::Type::None, ""}}; }; diff --git a/src/parser/query_builder.cpp b/src/parser/query_builder.cpp index 8a6ddf54..69eb8e54 100644 --- a/src/parser/query_builder.cpp +++ b/src/parser/query_builder.cpp @@ -164,11 +164,11 @@ void add_bool_constraint_to_query(Query &query, Predicate::Operator operatorType } void add_string_constraint_to_query(Query &query, - Predicate::Operator op, + Predicate::Comparison cmp, Columns &&column, std::string &&value) { - bool case_sensitive = true; - switch (op) { + bool case_sensitive = (cmp.option != Predicate::OperatorOption::CaseInsensitive); + switch (cmp.op) { case Predicate::Operator::BeginsWith: query.and_query(column.begins_with(value, case_sensitive)); break; @@ -190,11 +190,11 @@ void add_string_constraint_to_query(Query &query, } void add_string_constraint_to_query(realm::Query &query, - Predicate::Operator op, + Predicate::Comparison cmp, std::string &&value, Columns &&column) { - bool case_sensitive = true; - switch (op) { + bool case_sensitive = (cmp.option != Predicate::OperatorOption::CaseInsensitive); + switch (cmp.op) { case Predicate::Operator::Equal: query.and_query(column.equal(value, case_sensitive)); break; @@ -396,42 +396,42 @@ auto value_of_type_for_query(TableGetter&& tables, Value&& value, Arguments &arg } template -void do_add_comparison_to_query(Query &query, const Schema &schema, const ObjectSchema &object_schema, Predicate::Operator op, +void do_add_comparison_to_query(Query &query, const Schema &schema, const ObjectSchema &object_schema, Predicate::Comparison cmp, const PropertyExpression &expr, A &lhs, B &rhs, Arguments &args) { auto type = expr.prop->type; switch (type) { case PropertyTypeBool: - add_bool_constraint_to_query(query, op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_bool_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeDate: - add_numeric_constraint_to_query(query, op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeDouble: - add_numeric_constraint_to_query(query, op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeFloat: - add_numeric_constraint_to_query(query, op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeInt: - add_numeric_constraint_to_query(query, op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeString: - add_string_constraint_to_query(query, op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_string_constraint_to_query(query, cmp, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeData: - add_binary_constraint_to_query(query, op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_binary_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeObject: case PropertyTypeArray: - add_link_constraint_to_query(query, op, expr, link_argument(lhs, rhs, args)); + add_link_constraint_to_query(query, cmp.op, expr, link_argument(lhs, rhs, args)); break; default: { throw std::runtime_error((std::string)"Object type " + string_for_property_type(type) + " not supported"); @@ -446,11 +446,11 @@ void add_comparison_to_query(Query &query, const Predicate &pred, Arguments &arg auto object_schema = schema.find(type); if (t0 == parser::Expression::Type::KeyPath && t1 != parser::Expression::Type::KeyPath) { PropertyExpression expr(query, schema, object_schema, cmpr.expr[0].s); - do_add_comparison_to_query(query, schema, *object_schema, cmpr.op, expr, expr, cmpr.expr[1], args); + do_add_comparison_to_query(query, schema, *object_schema, cmpr, expr, expr, cmpr.expr[1], args); } else if (t0 != parser::Expression::Type::KeyPath && t1 == parser::Expression::Type::KeyPath) { PropertyExpression expr(query, schema, object_schema, cmpr.expr[1].s); - do_add_comparison_to_query(query, schema, *object_schema, cmpr.op, expr, cmpr.expr[0], expr, args); + do_add_comparison_to_query(query, schema, *object_schema, cmpr, expr, cmpr.expr[0], expr, args); } else { throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value"); diff --git a/tests/query.json b/tests/query.json index bc1d4bc3..e4edd4de 100644 --- a/tests/query.json +++ b/tests/query.json @@ -197,10 +197,10 @@ ["QueryThrows", "StringObject", "stringCol == 123"], ["QueryThrows", "StringObject", "stringCol CONTAINS $0", 1], - ["Disabled", "QueryCount", 3, "StringObject", "stringCol ==[c] 'a'"], - ["Disabled", "QueryCount", 5, "StringObject", "stringCol BEGINSWITH[c] 'A'"], - ["Disabled", "QueryCount", 4, "StringObject", "stringCol ENDSWITH[c] 'c'"], - ["Disabled", "QueryCount", 2, "StringObject", "stringCol CONTAINS[c] 'B'"] + ["QueryCount", 3, "StringObject", "stringCol ==[c] 'a'"], + ["QueryCount", 5, "StringObject", "stringCol BEGINSWITH[c] 'A'"], + ["QueryCount", 4, "StringObject", "stringCol ENDSWITH[c] 'c'"], + ["QueryCount", 2, "StringObject", "stringCol CONTAINS[c] 'B'"] ] }, From c98f192879ce9271ee4b87468f09b6a4be8250d8 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Mon, 28 Mar 2016 14:02:17 -0700 Subject: [PATCH 07/10] Move cmake_minimum_required() to the correct place It has to be before the call to project() or it doesn't do anything. --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dabfbc4c..0e34b85d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ +cmake_minimum_required(VERSION 3.2.0) + set(CMAKE_BUILD_TYPE Debug CACHE STRING "") project(realm-object-store) -cmake_minimum_required(VERSION 3.2.0) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") include(CompilerFlags) From 805fdc63a71d0ccf751d893a3e66cbd875ce05ab Mon Sep 17 00:00:00 2001 From: Ari Lazier Date: Fri, 1 Apr 2016 11:00:53 -0700 Subject: [PATCH 08/10] don't require optional or link properties when creating objects --- src/object_accessor.hpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/object_accessor.hpp b/src/object_accessor.hpp index a97568dd..61ef0a1d 100644 --- a/src/object_accessor.hpp +++ b/src/object_accessor.hpp @@ -208,10 +208,12 @@ namespace realm { case PropertyTypeArray: { realm::LinkViewRef link_view = m_row.get_linklist(column); link_view->clear(); - size_t count = Accessor::list_size(ctx, value); - for (size_t i = 0; i < count; i++) { - ValueType element = Accessor::list_value_at_index(ctx, value, i); - link_view->add(Accessor::to_object_index(ctx, m_realm, element, property.object_type, try_update)); + if (!Accessor::is_null(ctx, value)) { + size_t count = Accessor::list_size(ctx, value); + for (size_t i = 0; i < count; i++) { + ValueType element = Accessor::list_value_at_index(ctx, value, i); + link_view->add(Accessor::to_object_index(ctx, m_realm, element, property.object_type, try_update)); + } } break; } @@ -310,6 +312,9 @@ namespace realm { if (Accessor::has_default_value_for_property(ctx, realm.get(), object_schema, prop.name)) { object.set_property_value_impl(ctx, prop, Accessor::default_value_for_property(ctx, realm.get(), object_schema, prop.name), try_update); } + else if (prop.is_nullable || prop.type == PropertyTypeArray) { + object.set_property_value_impl(ctx, prop, Accessor::null_value(ctx), try_update); + } else { throw MissingPropertyValueException(object_schema.name, prop.name, "Missing property value for property " + prop.name); From 25d245deda19f31393642e3aa5084eaa04e78fa1 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Wed, 4 May 2016 10:09:32 -0700 Subject: [PATCH 09/10] Use erase-remove_if in RealmCoordinator::unregister_realm() --- src/impl/realm_coordinator.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/impl/realm_coordinator.cpp b/src/impl/realm_coordinator.cpp index a1e34f8c..3c624c32 100644 --- a/src/impl/realm_coordinator.cpp +++ b/src/impl/realm_coordinator.cpp @@ -152,17 +152,9 @@ RealmCoordinator::~RealmCoordinator() void RealmCoordinator::unregister_realm(Realm* realm) { std::lock_guard lock(m_realm_mutex); - for (size_t i = 0; i < m_weak_realm_notifiers.size(); ++i) { - auto& weak_realm_notifier = m_weak_realm_notifiers[i]; - if (!weak_realm_notifier.expired() && !weak_realm_notifier.is_for_realm(realm)) { - continue; - } - - if (i + 1 < m_weak_realm_notifiers.size()) { - weak_realm_notifier = std::move(m_weak_realm_notifiers.back()); - } - m_weak_realm_notifiers.pop_back(); - } + auto new_end = remove_if(begin(m_weak_realm_notifiers), end(m_weak_realm_notifiers), + [=](auto& notifier) { return notifier.expired() || notifier.is_for_realm(realm); }); + m_weak_realm_notifiers.erase(new_end, end(m_weak_realm_notifiers)); } void RealmCoordinator::clear_cache() From 507882d663d2bcd0f35e39c5e075675df598863b Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Wed, 27 Apr 2016 16:28:59 -0700 Subject: [PATCH 10/10] Update to core 0.100.1 --- CMakeLists.txt | 2 +- src/impl/transact_log_handler.cpp | 6 ++++-- src/object_accessor.hpp | 8 ++++---- src/object_schema.cpp | 19 +++++++++++++++++-- src/object_store.cpp | 12 +++++++----- src/parser/query_builder.cpp | 11 +++++------ src/parser/query_builder.hpp | 17 ++++++++--------- src/property.hpp | 22 +++++++++------------- src/results.cpp | 10 +++++----- src/results.hpp | 6 +++--- 10 files changed, 63 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e34b85d..b4c55f65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ include(CompilerFlags) include(Sanitizers) include(RealmCore) -set(REALM_CORE_VERSION "0.97.0" CACHE STRING "") +set(REALM_CORE_VERSION "0.100.1" CACHE STRING "") use_realm_core(${REALM_CORE_VERSION}) include_directories(${REALM_CORE_INCLUDE_DIR} src external/pegtl) diff --git a/src/impl/transact_log_handler.cpp b/src/impl/transact_log_handler.cpp index d99a7ea7..d95aa32d 100644 --- a/src/impl/transact_log_handler.cpp +++ b/src/impl/transact_log_handler.cpp @@ -124,7 +124,8 @@ public: bool set_double(size_t, size_t, double) { return true; } bool set_string(size_t, size_t, StringData) { return true; } bool set_binary(size_t, size_t, BinaryData) { return true; } - bool set_date_time(size_t, size_t, DateTime) { return true; } + bool set_olddatetime(size_t, size_t, OldDateTime) { return true; } + bool set_timestamp(size_t, size_t, Timestamp) { return true; } bool set_table(size_t, size_t) { return true; } bool set_mixed(size_t, size_t, const Mixed&) { return true; } bool set_link(size_t, size_t, size_t, size_t) { return true; } @@ -416,7 +417,8 @@ public: bool set_double(size_t col, size_t row, double) { return mark_dirty(row, col); } bool set_string(size_t col, size_t row, StringData) { return mark_dirty(row, col); } bool set_binary(size_t col, size_t row, BinaryData) { return mark_dirty(row, col); } - bool set_date_time(size_t col, size_t row, DateTime) { return mark_dirty(row, col); } + bool set_olddatetime(size_t col, size_t row, OldDateTime) { return mark_dirty(row, col); } + bool set_timestamp(size_t col, size_t row, Timestamp) { return mark_dirty(row, col); } bool set_table(size_t col, size_t row) { return mark_dirty(row, col); } bool set_mixed(size_t col, size_t row, const Mixed&) { return mark_dirty(row, col); } bool set_link(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); } diff --git a/src/object_accessor.hpp b/src/object_accessor.hpp index 61ef0a1d..85821a10 100644 --- a/src/object_accessor.hpp +++ b/src/object_accessor.hpp @@ -83,8 +83,8 @@ namespace realm { static ValueType from_string(ContextType, StringData); static std::string to_binary(ContextType, ValueType &); static ValueType from_binary(ContextType, BinaryData); - static DateTime to_datetime(ContextType, ValueType &); - static ValueType from_datetime(ContextType, DateTime); + static Timestamp to_timestamp(ContextType, ValueType &); + static ValueType from_timestamp(ContextType, Timestamp); static bool is_null(ContextType, ValueType &); static ValueType null_value(ContextType); @@ -194,7 +194,7 @@ namespace realm { m_row.set_mixed(column, Accessor::to_mixed(ctx, value)); break; case PropertyTypeDate: - m_row.set_datetime(column, Accessor::to_datetime(ctx, value)); + m_row.set_timestamp(column, Accessor::to_timestamp(ctx, value)); break; case PropertyTypeObject: { if (Accessor::is_null(ctx, value)) { @@ -246,7 +246,7 @@ namespace realm { case PropertyTypeAny: throw "Any not supported"; case PropertyTypeDate: - return Accessor::from_datetime(ctx, m_row.get_datetime(column)); + return Accessor::from_timestamp(ctx, m_row.get_timestamp(column)); case PropertyTypeObject: { auto linkObjectSchema = m_realm->config().schema->find(property.object_type); TableRef table = ObjectStore::table_for_object_type(m_realm->read_group(), linkObjectSchema->name); diff --git a/src/object_schema.cpp b/src/object_schema.cpp index 65dc7e85..f6d7ae2f 100644 --- a/src/object_schema.cpp +++ b/src/object_schema.cpp @@ -17,14 +17,29 @@ //////////////////////////////////////////////////////////////////////////// #include "object_schema.hpp" + #include "object_store.hpp" #include "property.hpp" -#include -#include +#include +#include using namespace realm; +#define ASSERT_PROPERTY_TYPE_VALUE(property, type) \ + static_assert(static_cast(PropertyType##property) == type_##type, \ + "PropertyType and DataType must have the same values") + +ASSERT_PROPERTY_TYPE_VALUE(Int, Int); +ASSERT_PROPERTY_TYPE_VALUE(Bool, Bool); +ASSERT_PROPERTY_TYPE_VALUE(Float, Float); +ASSERT_PROPERTY_TYPE_VALUE(Double, Double); +ASSERT_PROPERTY_TYPE_VALUE(Data, Binary); +ASSERT_PROPERTY_TYPE_VALUE(Date, Timestamp); +ASSERT_PROPERTY_TYPE_VALUE(Any, Mixed); +ASSERT_PROPERTY_TYPE_VALUE(Object, Link); +ASSERT_PROPERTY_TYPE_VALUE(Array, LinkList); + ObjectSchema::~ObjectSchema() = default; ObjectSchema::ObjectSchema(std::string name, std::string primary_key, std::initializer_list properties) diff --git a/src/object_store.cpp b/src/object_store.cpp index 8e9cbf95..94c309e8 100644 --- a/src/object_store.cpp +++ b/src/object_store.cpp @@ -21,7 +21,6 @@ #include "schema.hpp" #include -#include #include #include #include @@ -128,15 +127,18 @@ std::string ObjectStore::table_name_for_object_type(StringData object_type) { } TableRef ObjectStore::table_for_object_type(Group *group, StringData object_type) { - return group->get_table(table_name_for_object_type(object_type)); + auto name = table_name_for_object_type(object_type); + return group->get_table(name); } ConstTableRef ObjectStore::table_for_object_type(const Group *group, StringData object_type) { - return group->get_table(table_name_for_object_type(object_type)); + auto name = table_name_for_object_type(object_type); + return group->get_table(name); } TableRef ObjectStore::table_for_object_type_create_if_needed(Group *group, StringData object_type, bool &created) { - return group->get_or_add_table(table_name_for_object_type(object_type), &created); + auto name = table_name_for_object_type(object_type); + return group->get_or_add_table(name, &created); } static inline bool property_has_changed(Property const& p1, Property const& p2) { @@ -241,7 +243,7 @@ static void copy_property_values(const Property& source, const Property& destina copy_property_values(source, destination, table, &Table::get_binary, &Table::set_binary); break; case PropertyTypeDate: - copy_property_values(source, destination, table, &Table::get_datetime, &Table::set_datetime); + copy_property_values(source, destination, table, &Table::get_timestamp, &Table::set_timestamp); break; default: break; diff --git a/src/parser/query_builder.cpp b/src/parser/query_builder.cpp index 69eb8e54..f55a3b71 100644 --- a/src/parser/query_builder.cpp +++ b/src/parser/query_builder.cpp @@ -304,14 +304,13 @@ template struct ValueGetter; template -struct ValueGetter { - static Int convert(TableGetter&&, const parser::Expression & value, Arguments &args) +struct ValueGetter { + static Timestamp convert(TableGetter&&, const parser::Expression & value, Arguments &args) { if (value.type != parser::Expression::Type::Argument) { throw std::runtime_error("You must pass in a date argument to compare"); } - DateTime dt = args.datetime_for_argument(stot(value.s)); - return dt.get_datetime(); + return args.timestamp_for_argument(stot(value.s)); } }; @@ -406,8 +405,8 @@ void do_add_comparison_to_query(Query &query, const Schema &schema, const Object value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeDate: - add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), - value_of_type_for_query(expr.table_getter, rhs, args)); + add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), + value_of_type_for_query(expr.table_getter, rhs, args)); break; case PropertyTypeDouble: add_numeric_constraint_to_query(query, cmp.op, value_of_type_for_query(expr.table_getter, lhs, args), diff --git a/src/parser/query_builder.hpp b/src/parser/query_builder.hpp index 87043ee2..bccc2e13 100644 --- a/src/parser/query_builder.hpp +++ b/src/parser/query_builder.hpp @@ -19,11 +19,11 @@ #ifndef REALM_QUERY_BUILDER_HPP #define REALM_QUERY_BUILDER_HPP -#include -#include #include "parser.hpp" #include "object_accessor.hpp" +#include + namespace realm { class Query; class Schema; @@ -31,10 +31,10 @@ class Schema; namespace query_builder { class Arguments; -void apply_predicate(Query &query, const parser::Predicate &predicate, Arguments &arguments, const Schema &schema, const std::string &objectType); +void apply_predicate(Query &query, const parser::Predicate &predicate, Arguments &arguments, + const Schema &schema, const std::string &objectType); -class Arguments -{ +class Arguments { public: virtual bool bool_for_argument(size_t argument_index) = 0; virtual long long long_for_argument(size_t argument_index) = 0; @@ -42,14 +42,13 @@ class Arguments virtual double double_for_argument(size_t argument_index) = 0; virtual std::string string_for_argument(size_t argument_index) = 0; virtual std::string binary_for_argument(size_t argument_index) = 0; - virtual DateTime datetime_for_argument(size_t argument_index) = 0; + virtual Timestamp timestamp_for_argument(size_t argument_index) = 0; virtual size_t object_index_for_argument(size_t argument_index) = 0; virtual bool is_argument_null(size_t argument_index) = 0; }; template -class ArgumentConverter : public Arguments -{ +class ArgumentConverter : public Arguments { public: ArgumentConverter(ContextType context, std::vector arguments) : m_arguments(arguments), m_ctx(context) {}; @@ -60,7 +59,7 @@ class ArgumentConverter : public Arguments virtual double double_for_argument(size_t argument_index) { return Accessor::to_double(m_ctx, argument_at(argument_index)); } virtual std::string string_for_argument(size_t argument_index) { return Accessor::to_string(m_ctx, argument_at(argument_index)); } virtual std::string binary_for_argument(size_t argument_index) { return Accessor::to_binary(m_ctx, argument_at(argument_index)); } - virtual DateTime datetime_for_argument(size_t argument_index) { return Accessor::to_datetime(m_ctx, argument_at(argument_index)); } + virtual Timestamp timestamp_for_argument(size_t argument_index) { return Accessor::to_timestamp(m_ctx, argument_at(argument_index)); } virtual size_t object_index_for_argument(size_t argument_index) { return Accessor::to_existing_object_index(m_ctx, argument_at(argument_index)); } virtual bool is_argument_null(size_t argument_index) { return Accessor::is_null(m_ctx, argument_at(argument_index)); } diff --git a/src/property.hpp b/src/property.hpp index fa8b0ec3..25a3bda7 100644 --- a/src/property.hpp +++ b/src/property.hpp @@ -23,25 +23,15 @@ namespace realm { enum PropertyType { - /** Integer type: NSInteger, int, long, Int (Swift) */ PropertyTypeInt = 0, - /** Boolean type: BOOL, bool, Bool (Swift) */ PropertyTypeBool = 1, - /** Float type: CGFloat (32bit), float, Float (Swift) */ PropertyTypeFloat = 9, - /** Double type: CGFloat (64bit), double, Double (Swift) */ PropertyTypeDouble = 10, - /** String type: NSString, String (Swift) */ PropertyTypeString = 2, - /** Data type: NSData */ PropertyTypeData = 4, - /** Any type: id, **not supported in Swift** */ - PropertyTypeAny = 6, - /** Date type: NSDate */ - PropertyTypeDate = 7, - /** Object type. See [Realm Models](http://realm.io/docs/cocoa/latest/#models) */ + PropertyTypeAny = 6, // deprecated and will be removed in the future + PropertyTypeDate = 8, PropertyTypeObject = 12, - /** Array type. See [Realm Models](http://realm.io/docs/cocoa/latest/#models) */ PropertyTypeArray = 13, }; @@ -55,7 +45,13 @@ namespace realm { size_t table_column = -1; bool requires_index() const { return is_primary || is_indexed; } - bool is_indexable() const { return type == PropertyTypeInt || type == PropertyTypeBool || type == PropertyTypeString || type == PropertyTypeDate; } + bool is_indexable() const + { + return type == PropertyTypeInt + || type == PropertyTypeBool + || type == PropertyTypeDate + || type == PropertyTypeString; + } }; static inline const char *string_for_property_type(PropertyType type) { diff --git a/src/results.cpp b/src/results.cpp index bfdd8e87..fb01bed8 100644 --- a/src/results.cpp +++ b/src/results.cpp @@ -221,10 +221,10 @@ size_t Results::index_of(size_t row_ndx) REALM_UNREACHABLE(); } -template +template util::Optional Results::aggregate(size_t column, bool return_none_for_empty, Int agg_int, Float agg_float, - Double agg_double, DateTime agg_datetime) + Double agg_double, Timestamp agg_timestamp) { validate_read(); if (!m_table) @@ -252,7 +252,7 @@ util::Optional Results::aggregate(size_t column, bool return_none_for_emp switch (m_table->get_column_type(column)) { - case type_DateTime: return do_agg(agg_datetime); + case type_Timestamp: return do_agg(agg_timestamp); case type_Double: return do_agg(agg_double); case type_Float: return do_agg(agg_float); case type_Int: return do_agg(agg_int); @@ -267,7 +267,7 @@ util::Optional Results::max(size_t column) [=](auto const& table) { return table.maximum_int(column); }, [=](auto const& table) { return table.maximum_float(column); }, [=](auto const& table) { return table.maximum_double(column); }, - [=](auto const& table) { return table.maximum_datetime(column); }); + [=](auto const& table) { return table.maximum_timestamp(column); }); } util::Optional Results::min(size_t column) @@ -276,7 +276,7 @@ util::Optional Results::min(size_t column) [=](auto const& table) { return table.minimum_int(column); }, [=](auto const& table) { return table.minimum_float(column); }, [=](auto const& table) { return table.minimum_double(column); }, - [=](auto const& table) { return table.minimum_datetime(column); }); + [=](auto const& table) { return table.minimum_timestamp(column); }); } util::Optional Results::sum(size_t column) diff --git a/src/results.hpp b/src/results.hpp index 57767d86..c7501179 100644 --- a/src/results.hpp +++ b/src/results.hpp @@ -134,7 +134,7 @@ public: // Get the min/max/average/sum of the given column // All but sum() returns none when there are zero matching rows // sum() returns 0, except for when it returns none - // Throws UnsupportedColumnTypeException for sum/average on datetime or non-numeric column + // Throws UnsupportedColumnTypeException for sum/average on timestamp or non-numeric column // Throws OutOfBoundsIndexException for an out-of-bounds column util::Optional max(size_t column); util::Optional min(size_t column); @@ -225,10 +225,10 @@ private: void validate_read() const; void validate_write() const; - template + template util::Optional aggregate(size_t column, bool return_none_for_empty, Int agg_int, Float agg_float, - Double agg_double, DateTime agg_datetime); + Double agg_double, Timestamp agg_timestamp); void set_table_view(TableView&& tv); };