query.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*************************************************************************
  2. *
  3. * Copyright 2016 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_QUERY_HPP
  19. #define REALM_QUERY_HPP
  20. #include <cstdint>
  21. #include <cstdio>
  22. #include <climits>
  23. #include <algorithm>
  24. #include <string>
  25. #include <vector>
  26. #define REALM_MULTITHREAD_QUERY 0
  27. #if REALM_MULTITHREAD_QUERY
  28. // FIXME: Use our C++ thread abstraction API since it provides a much
  29. // higher level of encapsulation and safety.
  30. #include <pthread.h>
  31. #endif
  32. #include <realm/aggregate_ops.hpp>
  33. #include <realm/binary_data.hpp>
  34. #include <realm/column_type_traits.hpp>
  35. #include <realm/handover_defs.hpp>
  36. #include <realm/obj_list.hpp>
  37. #include <realm/table_ref.hpp>
  38. #include <realm/util/bind_ptr.hpp>
  39. #include <realm/util/serializer.hpp>
  40. namespace realm {
  41. // Pre-declarations
  42. class Array;
  43. class Expression;
  44. class Group;
  45. class LinkMap;
  46. class ParentNode;
  47. class Table;
  48. class TableView;
  49. class Timestamp;
  50. class Transaction;
  51. struct QueryGroup {
  52. enum class State {
  53. Default,
  54. OrCondition,
  55. OrConditionChildren,
  56. };
  57. QueryGroup() = default;
  58. QueryGroup(const QueryGroup&);
  59. QueryGroup& operator=(const QueryGroup&);
  60. QueryGroup(QueryGroup&&) = default;
  61. QueryGroup& operator=(QueryGroup&&) = default;
  62. std::unique_ptr<ParentNode> m_root_node;
  63. bool m_pending_not = false;
  64. State m_state = State::Default;
  65. };
  66. class Query final {
  67. public:
  68. Query(ConstTableRef table, TableView* tv = nullptr);
  69. Query(ConstTableRef table, std::unique_ptr<TableView>);
  70. Query(ConstTableRef table, const ObjList& list);
  71. Query(ConstTableRef table, LinkCollectionPtr&& list_ptr);
  72. Query();
  73. Query(std::unique_ptr<Expression>);
  74. ~Query() noexcept;
  75. Query(const Query& copy);
  76. Query& operator=(const Query& source);
  77. Query(Query&&);
  78. Query& operator=(Query&&);
  79. // Find links that point to a specific target row
  80. Query& links_to(ColKey column_key, ObjKey target_key);
  81. // Find links that point to a specific object (for Mixed columns)
  82. Query& links_to(ColKey column_key, ObjLink target_link);
  83. // Find links that point to specific target objects
  84. Query& links_to(ColKey column_key, const std::vector<ObjKey>& target_obj);
  85. // Find links that does not point to specific target objects
  86. Query& not_links_to(ColKey column_key, const std::vector<ObjKey>& target_obj);
  87. // Conditions: null
  88. Query& equal(ColKey column_key, null);
  89. Query& not_equal(ColKey column_key, null);
  90. // Conditions: int64_t
  91. Query& equal(ColKey column_key, int64_t value);
  92. Query& not_equal(ColKey column_key, int64_t value);
  93. Query& greater(ColKey column_key, int64_t value);
  94. Query& greater_equal(ColKey column_key, int64_t value);
  95. Query& less(ColKey column_key, int64_t value);
  96. Query& less_equal(ColKey column_key, int64_t value);
  97. Query& between(ColKey column_key, int64_t from, int64_t to);
  98. // Conditions: int (we need those because conversion from '1234' is ambiguous with float/double)
  99. Query& equal(ColKey column_key, int value);
  100. Query& not_equal(ColKey column_key, int value);
  101. Query& greater(ColKey column_key, int value);
  102. Query& greater_equal(ColKey column_key, int value);
  103. Query& less(ColKey column_key, int value);
  104. Query& less_equal(ColKey column_key, int value);
  105. Query& between(ColKey column_key, int from, int to);
  106. // Conditions: float
  107. Query& equal(ColKey column_key, float value);
  108. Query& not_equal(ColKey column_key, float value);
  109. Query& greater(ColKey column_key, float value);
  110. Query& greater_equal(ColKey column_key, float value);
  111. Query& less(ColKey column_key, float value);
  112. Query& less_equal(ColKey column_key, float value);
  113. Query& between(ColKey column_key, float from, float to);
  114. // Conditions: double
  115. Query& equal(ColKey column_key, double value);
  116. Query& not_equal(ColKey column_key, double value);
  117. Query& greater(ColKey column_key, double value);
  118. Query& greater_equal(ColKey column_key, double value);
  119. Query& less(ColKey column_key, double value);
  120. Query& less_equal(ColKey column_key, double value);
  121. Query& between(ColKey column_key, double from, double to);
  122. // Conditions: timestamp
  123. Query& equal(ColKey column_key, Timestamp value);
  124. Query& not_equal(ColKey column_key, Timestamp value);
  125. Query& greater(ColKey column_key, Timestamp value);
  126. Query& greater_equal(ColKey column_key, Timestamp value);
  127. Query& less_equal(ColKey column_key, Timestamp value);
  128. Query& less(ColKey column_key, Timestamp value);
  129. // Conditions: ObjectId
  130. Query& equal(ColKey column_key, ObjectId value);
  131. Query& not_equal(ColKey column_key, ObjectId value);
  132. Query& greater(ColKey column_key, ObjectId value);
  133. Query& greater_equal(ColKey column_key, ObjectId value);
  134. Query& less_equal(ColKey column_key, ObjectId value);
  135. Query& less(ColKey column_key, ObjectId value);
  136. // Conditions: UUID
  137. Query& equal(ColKey column_key, UUID value);
  138. Query& not_equal(ColKey column_key, UUID value);
  139. Query& greater(ColKey column_key, UUID value);
  140. Query& greater_equal(ColKey column_key, UUID value);
  141. Query& less_equal(ColKey column_key, UUID value);
  142. Query& less(ColKey column_key, UUID value);
  143. // Conditions: Decimal128
  144. Query& equal(ColKey column_key, Decimal128 value);
  145. Query& not_equal(ColKey column_key, Decimal128 value);
  146. Query& greater(ColKey column_key, Decimal128 value);
  147. Query& greater_equal(ColKey column_key, Decimal128 value);
  148. Query& less_equal(ColKey column_key, Decimal128 value);
  149. Query& less(ColKey column_key, Decimal128 value);
  150. Query& between(ColKey column_key, Decimal128 from, Decimal128 to);
  151. // Conditions: Mixed
  152. Query& equal(ColKey column_key, Mixed value, bool case_sensitive = true);
  153. Query& not_equal(ColKey column_key, Mixed value, bool case_sensitive = true);
  154. Query& greater(ColKey column_key, Mixed value);
  155. Query& greater_equal(ColKey column_key, Mixed value);
  156. Query& less(ColKey column_key, Mixed value);
  157. Query& less_equal(ColKey column_key, Mixed value);
  158. Query& begins_with(ColKey column_key, Mixed value, bool case_sensitive = true);
  159. Query& ends_with(ColKey column_key, Mixed value, bool case_sensitive = true);
  160. Query& contains(ColKey column_key, Mixed value, bool case_sensitive = true);
  161. Query& like(ColKey column_key, Mixed value, bool case_sensitive = true);
  162. // Conditions: size
  163. Query& size_equal(ColKey column_key, int64_t value);
  164. Query& size_not_equal(ColKey column_key, int64_t value);
  165. Query& size_greater(ColKey column_key, int64_t value);
  166. Query& size_greater_equal(ColKey column_key, int64_t value);
  167. Query& size_less_equal(ColKey column_key, int64_t value);
  168. Query& size_less(ColKey column_key, int64_t value);
  169. Query& size_between(ColKey column_key, int64_t from, int64_t to);
  170. // Conditions: bool
  171. Query& equal(ColKey column_key, bool value);
  172. Query& not_equal(ColKey column_key, bool value);
  173. // Conditions: strings
  174. Query& equal(ColKey column_key, StringData value, bool case_sensitive = true);
  175. Query& not_equal(ColKey column_key, StringData value, bool case_sensitive = true);
  176. Query& begins_with(ColKey column_key, StringData value, bool case_sensitive = true);
  177. Query& ends_with(ColKey column_key, StringData value, bool case_sensitive = true);
  178. Query& contains(ColKey column_key, StringData value, bool case_sensitive = true);
  179. Query& like(ColKey column_key, StringData value, bool case_sensitive = true);
  180. Query& fulltext(ColKey column_key, StringData value);
  181. Query& fulltext(ColKey column_key, StringData value, const LinkMap&);
  182. // These are shortcuts for equal(StringData(c_str)) and
  183. // not_equal(StringData(c_str)), and are needed to avoid unwanted
  184. // implicit conversion of char* to bool.
  185. Query& equal(ColKey column_key, const char* c_str, bool case_sensitive = true);
  186. Query& not_equal(ColKey column_key, const char* c_str, bool case_sensitive = true);
  187. // Conditions: binary data
  188. Query& equal(ColKey column_key, BinaryData value, bool case_sensitive = true);
  189. Query& not_equal(ColKey column_key, BinaryData value, bool case_sensitive = true);
  190. Query& begins_with(ColKey column_key, BinaryData value, bool case_sensitive = true);
  191. Query& ends_with(ColKey column_key, BinaryData value, bool case_sensitive = true);
  192. Query& contains(ColKey column_key, BinaryData value, bool case_sensitive = true);
  193. Query& like(ColKey column_key, BinaryData b, bool case_sensitive = true);
  194. // Conditions: untyped column vs column comparison
  195. // if the column types are not comparable, an exception is thrown
  196. Query& equal(ColKey column_key1, ColKey column_key2);
  197. Query& less(ColKey column_key1, ColKey column_key2);
  198. Query& less_equal(ColKey column_key1, ColKey column_key2);
  199. Query& greater(ColKey column_key1, ColKey column_key2);
  200. Query& greater_equal(ColKey column_key1, ColKey column_key2);
  201. Query& not_equal(ColKey column_key1, ColKey column_key2);
  202. // Negation
  203. Query& Not();
  204. // Grouping
  205. Query& group();
  206. Query& end_group();
  207. Query& Or();
  208. Query& and_query(const Query& q);
  209. Query& and_query(Query&& q);
  210. Query operator||(const Query& q);
  211. Query operator&&(const Query& q);
  212. Query operator!();
  213. // Searching
  214. ObjKey find() const;
  215. TableView find_all(size_t limit = size_t(-1)) const;
  216. // Aggregates
  217. size_t count() const;
  218. TableView find_all(const DescriptorOrdering& descriptor) const;
  219. size_t count(const DescriptorOrdering& descriptor) const;
  220. // Aggregates return nullopt if the operation is not supported on the given column
  221. // Everything but `sum` returns `some(null)` if there are no non-null values
  222. // Sum returns `some(0)` if there are no non-null values.
  223. std::optional<Mixed> sum(ColKey col_key) const;
  224. std::optional<Mixed> min(ColKey col_key, ObjKey* = nullptr) const;
  225. std::optional<Mixed> max(ColKey col_key, ObjKey* = nullptr) const;
  226. std::optional<Mixed> avg(ColKey col_key, size_t* value_count = nullptr) const;
  227. // Deletion
  228. size_t remove() const;
  229. #if REALM_MULTITHREAD_QUERY
  230. // Multi-threading
  231. TableView find_all_multi(size_t start = 0, size_t end = size_t(-1));
  232. TableView find_all_multi(size_t start = 0, size_t end = size_t(-1)) const;
  233. int set_threads(unsigned int threadcount);
  234. #endif
  235. const ConstTableRef& get_table() const noexcept
  236. {
  237. return m_table;
  238. }
  239. ConstTableRef& get_table()
  240. {
  241. return m_table;
  242. }
  243. void get_outside_versions(TableVersions&) const;
  244. // True if matching rows are guaranteed to be returned in table order.
  245. bool produces_results_in_table_order() const
  246. {
  247. return !m_view;
  248. }
  249. // Get the ObjKey of the object which owns the restricting view, or null
  250. // if that is not applicable
  251. ObjKey view_owner_obj_key() const noexcept
  252. {
  253. return m_view ? m_view->get_owning_obj().get_key() : ObjKey{};
  254. }
  255. // Calls sync_if_needed on the restricting view, if present.
  256. // Returns the current version of the table(s) this query depends on,
  257. // or empty vector if the query is not associated with a table.
  258. TableVersions sync_view_if_needed() const;
  259. std::string validate() const;
  260. std::string get_description() const;
  261. std::string get_description_safe() const noexcept;
  262. Query& set_ordering(util::bind_ptr<DescriptorOrdering> ordering);
  263. // This will remove the ordering from the Query object
  264. util::bind_ptr<DescriptorOrdering> get_ordering();
  265. bool eval_object(const Obj& obj) const;
  266. private:
  267. void create();
  268. void init() const;
  269. size_t find_internal(size_t start = 0, size_t end = size_t(-1)) const;
  270. void handle_pending_not();
  271. void set_table(TableRef tr);
  272. std::string get_description(util::serializer::SerialisationState& state) const;
  273. public:
  274. std::unique_ptr<Query> clone_for_handover(Transaction* tr, PayloadPolicy policy) const
  275. {
  276. return std::make_unique<Query>(this, tr, policy);
  277. }
  278. Query(const Query* source, Transaction* tr, PayloadPolicy policy);
  279. Query(const Query& source, Transaction* tr, PayloadPolicy policy)
  280. : Query(&source, tr, policy)
  281. {
  282. }
  283. private:
  284. void add_expression_node(std::unique_ptr<Expression>);
  285. template <typename TConditionFunction, class T>
  286. Query& add_condition(ColKey column_key, T value);
  287. template <typename TConditionFunction>
  288. Query& add_size_condition(ColKey column_key, int64_t value);
  289. template <typename T>
  290. void aggregate(QueryStateBase& st, ColKey column_key) const;
  291. size_t find_best_node(ParentNode* pn) const;
  292. void aggregate_internal(ParentNode* pn, QueryStateBase* st, size_t start, size_t end,
  293. ArrayPayload* source_column) const;
  294. void do_find_all(QueryStateBase& st) const;
  295. size_t do_count(size_t limit = size_t(-1)) const;
  296. void delete_nodes() noexcept;
  297. bool has_conditions() const
  298. {
  299. return m_groups.size() > 0 && m_groups[0].m_root_node;
  300. }
  301. ParentNode* root_node() const
  302. {
  303. REALM_ASSERT(m_groups.size());
  304. return m_groups[0].m_root_node.get();
  305. }
  306. void add_node(std::unique_ptr<ParentNode>);
  307. friend class Table;
  308. friend class TableView;
  309. friend class SubQueryCount;
  310. friend class PrimitiveListCount;
  311. template <class>
  312. friend class AggregateHelper;
  313. std::string error_code;
  314. std::vector<QueryGroup> m_groups;
  315. mutable std::vector<TableKey> m_table_keys;
  316. TableRef m_table;
  317. // points to the base class of the restricting view. If the restricting
  318. // view is a link view, m_source_collection is non-zero. If it is a table view,
  319. // m_source_table_view is non-zero.
  320. ObjList* m_view = nullptr;
  321. // At most one of these can be non-zero, and if so the non-zero one indicates the restricting view.
  322. //
  323. // m_source_collection is a pointer to a collection which must also be a ObjList*
  324. // this includes: LnkLst, LnkSet, and DictionaryLinkValues. It cannot be a list of primitives because
  325. // it is used to populate a query through a collection of objects and there are asserts for this.
  326. LinkCollectionPtr m_source_collection; // collections are owned by the query.
  327. TableView* m_source_table_view = nullptr; // table views are not refcounted, and not owned by the query.
  328. std::unique_ptr<TableView> m_owned_source_table_view; // <--- except when indicated here
  329. util::bind_ptr<DescriptorOrdering> m_ordering;
  330. };
  331. // Implementation:
  332. inline Query& Query::equal(ColKey column_key, const char* c_str, bool case_sensitive)
  333. {
  334. return equal(column_key, StringData(c_str), case_sensitive);
  335. }
  336. inline Query& Query::not_equal(ColKey column_key, const char* c_str, bool case_sensitive)
  337. {
  338. return not_equal(column_key, StringData(c_str), case_sensitive);
  339. }
  340. } // namespace realm
  341. #endif // REALM_QUERY_HPP