table.hpp 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378
  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_TABLE_HPP
  19. #define REALM_TABLE_HPP
  20. #include "external/mpark/variant.hpp"
  21. #include <algorithm>
  22. #include <map>
  23. #include <utility>
  24. #include <typeinfo>
  25. #include <memory>
  26. #include <mutex>
  27. #include <realm/util/features.h>
  28. #include <realm/util/function_ref.hpp>
  29. #include <realm/util/thread.hpp>
  30. #include <realm/table_ref.hpp>
  31. #include <realm/spec.hpp>
  32. #include <realm/query.hpp>
  33. #include <realm/cluster_tree.hpp>
  34. #include <realm/keys.hpp>
  35. #include <realm/global_key.hpp>
  36. // Only set this to one when testing the code paths that exercise object ID
  37. // hash collisions. It artificially limits the "optimistic" local ID to use
  38. // only the lower 15 bits of the ID rather than the lower 63 bits, making it
  39. // feasible to generate collisions within reasonable time.
  40. #define REALM_EXERCISE_OBJECT_ID_COLLISION 0
  41. namespace realm {
  42. class BacklinkColumn;
  43. template <class>
  44. class BacklinkCount;
  45. class TableView;
  46. class Group;
  47. class SortDescriptor;
  48. class TableView;
  49. template <class>
  50. class Columns;
  51. template <class>
  52. class SubQuery;
  53. class ColKeys;
  54. struct GlobalKey;
  55. class LinkChain;
  56. class Subexpr;
  57. class StringIndex;
  58. struct Link {
  59. };
  60. typedef Link BackLink;
  61. namespace _impl {
  62. class TableFriend;
  63. }
  64. namespace util {
  65. class Logger;
  66. }
  67. namespace query_parser {
  68. class Arguments;
  69. class KeyPathMapping;
  70. class ParserDriver;
  71. } // namespace query_parser
  72. enum class ExpressionComparisonType : unsigned char {
  73. Any,
  74. All,
  75. None,
  76. };
  77. class Table {
  78. public:
  79. /// The type of tables supported by a realm.
  80. /// Note: Any change to this enum is a file-format breaking change.
  81. /// Note: Enumeration value assignments must be kept in sync with
  82. /// <realm/object-store/object_schema.hpp>.
  83. enum class Type : uint8_t { TopLevel = 0, Embedded = 0x1, TopLevelAsymmetric = 0x2 };
  84. constexpr static uint8_t table_type_mask = 0x3;
  85. /// Construct a new freestanding top-level table with static
  86. /// lifetime. For debugging only.
  87. Table(Allocator& = Allocator::get_default());
  88. /// Construct a copy of the specified table as a new freestanding
  89. /// top-level table with static lifetime. For debugging only.
  90. Table(const Table&, Allocator& = Allocator::get_default());
  91. ~Table() noexcept;
  92. Allocator& get_alloc() const;
  93. /// Get the name of this table, if it has one. Only group-level tables have
  94. /// names. For a table of any other kind, this function returns the empty
  95. /// string.
  96. StringData get_name() const noexcept;
  97. // Get table name with class prefix removed
  98. StringData get_class_name() const noexcept;
  99. const char* get_state() const noexcept;
  100. /// If this table is a group-level table, the parent group is returned,
  101. /// otherwise null is returned.
  102. Group* get_parent_group() const noexcept;
  103. // Whether or not elements can be null.
  104. bool is_nullable(ColKey col_key) const;
  105. // Whether or not the column is a list.
  106. bool is_list(ColKey col_key) const;
  107. //@{
  108. /// Conventience functions for inspecting the dynamic table type.
  109. ///
  110. bool is_embedded() const noexcept; // true if table holds embedded objects
  111. bool is_asymmetric() const noexcept; // true if table is asymmetric
  112. Type get_table_type() const noexcept;
  113. size_t get_column_count() const noexcept;
  114. DataType get_column_type(ColKey column_key) const;
  115. StringData get_column_name(ColKey column_key) const;
  116. ColumnAttrMask get_column_attr(ColKey column_key) const noexcept;
  117. DataType get_dictionary_key_type(ColKey column_key) const noexcept;
  118. ColKey get_column_key(StringData name) const noexcept;
  119. ColKeys get_column_keys() const;
  120. typedef util::Optional<std::pair<ConstTableRef, ColKey>> BacklinkOrigin;
  121. BacklinkOrigin find_backlink_origin(StringData origin_table_name, StringData origin_col_name) const noexcept;
  122. BacklinkOrigin find_backlink_origin(ColKey backlink_col) const noexcept;
  123. std::vector<std::pair<TableKey, ColKey>> get_incoming_link_columns() const noexcept;
  124. //@}
  125. // Primary key columns
  126. ColKey get_primary_key_column() const;
  127. void set_primary_key_column(ColKey col);
  128. void validate_primary_column();
  129. //@{
  130. /// Convenience functions for manipulating the dynamic table type.
  131. ///
  132. static const size_t max_column_name_length = 63;
  133. static const uint64_t max_num_columns = 0xFFFFUL; // <-- must be power of two -1
  134. ColKey add_column(DataType type, StringData name, bool nullable = false);
  135. ColKey add_column(Table& target, StringData name);
  136. ColKey add_column_list(DataType type, StringData name, bool nullable = false);
  137. ColKey add_column_list(Table& target, StringData name);
  138. ColKey add_column_set(DataType type, StringData name, bool nullable = false);
  139. ColKey add_column_set(Table& target, StringData name);
  140. ColKey add_column_dictionary(DataType type, StringData name, bool nullable = false,
  141. DataType key_type = type_String);
  142. ColKey add_column_dictionary(Table& target, StringData name, DataType key_type = type_String);
  143. [[deprecated("Use add_column(Table&) or add_column_list(Table&) instead.")]] //
  144. ColKey
  145. add_column_link(DataType type, StringData name, Table& target);
  146. void remove_column(ColKey col_key);
  147. void rename_column(ColKey col_key, StringData new_name);
  148. bool valid_column(ColKey col_key) const noexcept;
  149. void check_column(ColKey col_key) const
  150. {
  151. if (REALM_UNLIKELY(!valid_column(col_key)))
  152. throw InvalidColumnKey();
  153. }
  154. // Change the type of a table. Only allowed to switch to/from TopLevel from/to Embedded.
  155. void set_table_type(Type new_type, bool handle_backlinks = false);
  156. //@}
  157. /// True for `col_type_Link` and `col_type_LinkList`.
  158. static bool is_link_type(ColumnType) noexcept;
  159. //@{
  160. /// has_search_index() returns true if, and only if a search index has been
  161. /// added to the specified column. Rather than throwing, it returns false if
  162. /// the table accessor is detached or the specified index is out of range.
  163. ///
  164. /// add_search_index() adds a search index to the specified column of the
  165. /// table. It has no effect if a search index has already been added to the
  166. /// specified column (idempotency).
  167. ///
  168. /// remove_search_index() removes the search index from the specified column
  169. /// of the table. It has no effect if the specified column has no search
  170. /// index. The search index cannot be removed from the primary key of a
  171. /// table.
  172. ///
  173. /// \param col_key The key of a column of the table.
  174. IndexType search_index_type(ColKey col_key) const noexcept;
  175. bool has_search_index(ColKey col_key) const noexcept
  176. {
  177. return search_index_type(col_key) == IndexType::General;
  178. }
  179. void add_search_index(ColKey col_key, IndexType type = IndexType::General);
  180. void add_fulltext_index(ColKey col_key)
  181. {
  182. add_search_index(col_key, IndexType::Fulltext);
  183. }
  184. void remove_search_index(ColKey col_key);
  185. void enumerate_string_column(ColKey col_key);
  186. bool is_enumerated(ColKey col_key) const noexcept;
  187. bool contains_unique_values(ColKey col_key) const;
  188. //@}
  189. /// If the specified column is optimized to store only unique values, then
  190. /// this function returns the number of unique values currently
  191. /// stored. Otherwise it returns zero. This function is mainly intended for
  192. /// debugging purposes.
  193. size_t get_num_unique_values(ColKey col_key) const;
  194. template <class T>
  195. Columns<T> column(ColKey col_key, util::Optional<ExpressionComparisonType> = util::none) const;
  196. template <class T>
  197. Columns<T> column(const Table& origin, ColKey origin_col_key) const;
  198. // BacklinkCount is a total count per row and therefore not attached to a specific column
  199. template <class T>
  200. BacklinkCount<T> get_backlink_count() const;
  201. template <class T>
  202. SubQuery<T> column(ColKey col_key, Query subquery) const;
  203. template <class T>
  204. SubQuery<T> column(const Table& origin, ColKey origin_col_key, Query subquery) const;
  205. // Table size and deletion
  206. bool is_empty() const noexcept;
  207. size_t size() const noexcept
  208. {
  209. return m_clusters.size();
  210. }
  211. size_t nb_unresolved() const noexcept
  212. {
  213. return m_tombstones ? m_tombstones->size() : 0;
  214. }
  215. //@{
  216. /// Object handling.
  217. enum class UpdateMode { never, changed, all };
  218. // Create an object with key. If the key is omitted, a key will be generated by the system
  219. Obj create_object(ObjKey key = {}, const FieldValues& = {});
  220. // Create an object with specific GlobalKey - or return already existing object
  221. // Potential tombstone will be resurrected
  222. Obj create_object(GlobalKey object_id, const FieldValues& = {});
  223. // Create an object with primary key. If an object with the given primary key already exists, it
  224. // will be returned and did_create (if supplied) will be set to false.
  225. // Potential tombstone will be resurrected
  226. Obj create_object_with_primary_key(const Mixed& primary_key, FieldValues&&, UpdateMode mode = UpdateMode::all,
  227. bool* did_create = nullptr);
  228. Obj create_object_with_primary_key(const Mixed& primary_key, bool* did_create = nullptr)
  229. {
  230. return create_object_with_primary_key(primary_key, {{}}, UpdateMode::all, did_create);
  231. }
  232. // Return key for existing object or return null key.
  233. ObjKey find_primary_key(Mixed value) const;
  234. // Return ObjKey for object identified by id. If objects does not exist, return null key
  235. // Important: This function must not be called for tables with primary keys.
  236. ObjKey get_objkey(GlobalKey id) const;
  237. // Return key for existing object or return unresolved key.
  238. // Important: This is to be used ONLY by the Sync client. SDKs should NEVER
  239. // observe an unresolved key. Ever.
  240. ObjKey get_objkey_from_primary_key(const Mixed& primary_key);
  241. // Return key for existing object or return unresolved key.
  242. // Important: This is to be used ONLY by the Sync client. SDKs should NEVER
  243. // observe an unresolved key. Ever.
  244. // Important (2): This function must not be called for tables with primary keys.
  245. ObjKey get_objkey_from_global_key(GlobalKey key);
  246. /// Create a number of objects and add corresponding keys to a vector
  247. void create_objects(size_t number, std::vector<ObjKey>& keys);
  248. /// Create a number of objects with keys supplied
  249. void create_objects(const std::vector<ObjKey>& keys);
  250. /// Does the key refer to an object within the table?
  251. bool is_valid(ObjKey key) const noexcept
  252. {
  253. return key && m_clusters.is_valid(key);
  254. }
  255. GlobalKey get_object_id(ObjKey key) const;
  256. Obj get_object(ObjKey key) const
  257. {
  258. REALM_ASSERT(!key.is_unresolved());
  259. return m_clusters.get(key);
  260. }
  261. Obj try_get_object(ObjKey key) const noexcept
  262. {
  263. return m_clusters.try_get_obj(key);
  264. }
  265. Obj get_object(size_t ndx) const
  266. {
  267. return m_clusters.get(ndx);
  268. }
  269. // Get object based on primary key
  270. Obj get_object_with_primary_key(Mixed pk) const;
  271. // Get primary key based on ObjKey
  272. Mixed get_primary_key(ObjKey key) const;
  273. // Get logical index for object. This function is not very efficient
  274. size_t get_object_ndx(ObjKey key) const noexcept
  275. {
  276. return m_clusters.get_ndx(key);
  277. }
  278. void dump_objects();
  279. bool traverse_clusters(ClusterTree::TraverseFunction func) const
  280. {
  281. return m_clusters.traverse(func);
  282. }
  283. /// remove_object() removes the specified object from the table.
  284. /// Any links from the specified object into objects residing in an embedded
  285. /// table will cause those objects to be deleted as well, and so on recursively.
  286. void remove_object(ObjKey key);
  287. /// remove_object_recursive() will delete linked rows if the removed link was the
  288. /// last one holding on to the row in question. This will be done recursively.
  289. void remove_object_recursive(ObjKey key);
  290. // Invalidate object. To be used by the Sync client.
  291. // - turns the object into a tombstone if links exist
  292. // - otherwise works just as remove_object()
  293. ObjKey invalidate_object(ObjKey key);
  294. // Remove several objects
  295. void batch_erase_objects(std::vector<ObjKey>& keys);
  296. Obj try_get_tombstone(ObjKey key) const
  297. {
  298. REALM_ASSERT(key.is_unresolved());
  299. REALM_ASSERT(m_tombstones);
  300. return m_tombstones->try_get_obj(key);
  301. }
  302. void clear();
  303. using Iterator = ClusterTree::Iterator;
  304. Iterator begin() const;
  305. Iterator end() const;
  306. void remove_object(const Iterator& it)
  307. {
  308. remove_object(it->get_key());
  309. }
  310. //@}
  311. TableRef get_link_target(ColKey column_key) noexcept;
  312. ConstTableRef get_link_target(ColKey column_key) const noexcept;
  313. static const size_t max_string_size = 0xFFFFF8 - Array::header_size - 1;
  314. static const size_t max_binary_size = 0xFFFFF8 - Array::header_size;
  315. static constexpr int_fast64_t max_integer = std::numeric_limits<int64_t>::max();
  316. static constexpr int_fast64_t min_integer = std::numeric_limits<int64_t>::min();
  317. /// Only group-level unordered tables can be used as origins or targets of
  318. /// links.
  319. bool is_group_level() const noexcept;
  320. /// A Table accessor obtained from a frozen transaction is also frozen.
  321. bool is_frozen() const noexcept
  322. {
  323. return m_is_frozen;
  324. }
  325. /// If this table is a group-level table, then this function returns the
  326. /// index of this table within the group. Otherwise it returns realm::npos.
  327. size_t get_index_in_group() const noexcept;
  328. TableKey get_key() const noexcept;
  329. uint64_t allocate_sequence_number();
  330. // Used by upgrade
  331. void set_sequence_number(uint64_t seq);
  332. void set_collision_map(ref_type ref);
  333. // Used for testing purposes.
  334. void set_col_key_sequence_number(uint64_t seq);
  335. // Get the key of this table directly, without needing a Table accessor.
  336. static TableKey get_key_direct(Allocator& alloc, ref_type top_ref);
  337. // Aggregate functions
  338. size_t count_int(ColKey col_key, int64_t value) const;
  339. size_t count_string(ColKey col_key, StringData value) const;
  340. size_t count_float(ColKey col_key, float value) const;
  341. size_t count_double(ColKey col_key, double value) const;
  342. size_t count_decimal(ColKey col_key, Decimal128 value) const;
  343. // Aggregates return nullopt if the operation is not supported on the given column
  344. // Everything but `sum` returns `some(null)` if there are no non-null values
  345. // Sum returns `some(0)` if there are no non-null values.
  346. std::optional<Mixed> sum(ColKey col_key) const;
  347. std::optional<Mixed> min(ColKey col_key, ObjKey* = nullptr) const;
  348. std::optional<Mixed> max(ColKey col_key, ObjKey* = nullptr) const;
  349. std::optional<Mixed> avg(ColKey col_key, size_t* value_count = nullptr) const;
  350. // Will return pointer to search index accessor. Will return nullptr if no index
  351. StringIndex* get_search_index(ColKey col) const noexcept
  352. {
  353. check_column(col);
  354. return m_index_accessors[col.get_index().val].get();
  355. }
  356. template <class T>
  357. ObjKey find_first(ColKey col_key, T value) const;
  358. ObjKey find_first_int(ColKey col_key, int64_t value) const;
  359. ObjKey find_first_bool(ColKey col_key, bool value) const;
  360. ObjKey find_first_timestamp(ColKey col_key, Timestamp value) const;
  361. ObjKey find_first_object_id(ColKey col_key, ObjectId value) const;
  362. ObjKey find_first_float(ColKey col_key, float value) const;
  363. ObjKey find_first_double(ColKey col_key, double value) const;
  364. ObjKey find_first_decimal(ColKey col_key, Decimal128 value) const;
  365. ObjKey find_first_string(ColKey col_key, StringData value) const;
  366. ObjKey find_first_binary(ColKey col_key, BinaryData value) const;
  367. ObjKey find_first_null(ColKey col_key) const;
  368. ObjKey find_first_uuid(ColKey col_key, UUID value) const;
  369. // TableView find_all_link(Key target_key);
  370. TableView find_all_int(ColKey col_key, int64_t value);
  371. TableView find_all_int(ColKey col_key, int64_t value) const;
  372. TableView find_all_bool(ColKey col_key, bool value);
  373. TableView find_all_bool(ColKey col_key, bool value) const;
  374. TableView find_all_float(ColKey col_key, float value);
  375. TableView find_all_float(ColKey col_key, float value) const;
  376. TableView find_all_double(ColKey col_key, double value);
  377. TableView find_all_double(ColKey col_key, double value) const;
  378. TableView find_all_string(ColKey col_key, StringData value);
  379. TableView find_all_string(ColKey col_key, StringData value) const;
  380. TableView find_all_binary(ColKey col_key, BinaryData value);
  381. TableView find_all_binary(ColKey col_key, BinaryData value) const;
  382. TableView find_all_null(ColKey col_key);
  383. TableView find_all_null(ColKey col_key) const;
  384. TableView find_all_fulltext(ColKey col_key, StringData value) const;
  385. TableView get_sorted_view(ColKey col_key, bool ascending = true);
  386. TableView get_sorted_view(ColKey col_key, bool ascending = true) const;
  387. TableView get_sorted_view(SortDescriptor order);
  388. TableView get_sorted_view(SortDescriptor order) const;
  389. // Report the current content version. This is a 64-bit value which is bumped whenever
  390. // the content in the table changes.
  391. uint_fast64_t get_content_version() const noexcept;
  392. // Report the current instance version. This is a 64-bit value which is bumped
  393. // whenever the table accessor is recycled.
  394. uint_fast64_t get_instance_version() const noexcept;
  395. // Report the current storage version. This is a 64-bit value which is bumped
  396. // whenever the location in memory of any part of the table changes.
  397. uint_fast64_t get_storage_version(uint64_t instance_version) const;
  398. uint_fast64_t get_storage_version() const;
  399. void bump_storage_version() const noexcept;
  400. void bump_content_version() const noexcept;
  401. // Change the nullability of the column identified by col_key.
  402. // This might result in the creation of a new column and deletion of the old.
  403. // The column key to use going forward is returned.
  404. // If the conversion is from nullable to non-nullable, throw_on_null determines
  405. // the reaction to encountering a null value: If clear, null values will be
  406. // converted to default values. If set, a 'column_not_nullable' is thrown and the
  407. // table is unchanged.
  408. ColKey set_nullability(ColKey col_key, bool nullable, bool throw_on_null);
  409. // Iterate through (subset of) columns. The supplied function may abort iteration
  410. // by returning 'IteratorControl::Stop' (early out).
  411. template <typename Func>
  412. bool for_each_and_every_column(Func func) const
  413. {
  414. for (auto col_key : m_leaf_ndx2colkey) {
  415. if (!col_key)
  416. continue;
  417. if (func(col_key) == IteratorControl::Stop)
  418. return true;
  419. }
  420. return false;
  421. }
  422. template <typename Func>
  423. bool for_each_public_column(Func func) const
  424. {
  425. for (auto col_key : m_leaf_ndx2colkey) {
  426. if (!col_key)
  427. continue;
  428. if (col_key.get_type() == col_type_BackLink)
  429. continue;
  430. if (func(col_key) == IteratorControl::Stop)
  431. return true;
  432. }
  433. return false;
  434. }
  435. template <typename Func>
  436. bool for_each_backlink_column(Func func) const
  437. {
  438. // Could be optimized - to not iterate through all non-backlink columns:
  439. for (auto col_key : m_leaf_ndx2colkey) {
  440. if (!col_key)
  441. continue;
  442. if (col_key.get_type() != col_type_BackLink)
  443. continue;
  444. if (func(col_key) == IteratorControl::Stop)
  445. return true;
  446. }
  447. return false;
  448. }
  449. private:
  450. template <class T>
  451. TableView find_all(ColKey col_key, T value);
  452. void build_column_mapping();
  453. ColKey generate_col_key(ColumnType ct, ColumnAttrMask attrs);
  454. void convert_column(ColKey from, ColKey to, bool throw_on_null);
  455. template <class F, class T>
  456. void change_nullability(ColKey from, ColKey to, bool throw_on_null);
  457. template <class F, class T>
  458. void change_nullability_list(ColKey from, ColKey to, bool throw_on_null);
  459. Obj create_linked_object();
  460. // Change the embedded property of a table. If switching to being embedded, the table must
  461. // not have a primary key and all objects must have exactly 1 backlink.
  462. void set_embedded(bool embedded, bool handle_backlinks);
  463. /// Changes type unconditionally. Called only from Group::do_get_or_add_table()
  464. void do_set_table_type(Type table_type);
  465. public:
  466. // mapping between index used in leaf nodes (leaf_ndx) and index used in spec (spec_ndx)
  467. // as well as the full column key. A leaf_ndx can be obtained directly from the column key
  468. size_t colkey2spec_ndx(ColKey key) const;
  469. size_t leaf_ndx2spec_ndx(ColKey::Idx idx) const;
  470. ColKey::Idx spec_ndx2leaf_ndx(size_t idx) const;
  471. ColKey leaf_ndx2colkey(ColKey::Idx idx) const;
  472. ColKey spec_ndx2colkey(size_t ndx) const;
  473. // Queries
  474. // Using where(tv) is the new method to perform queries on TableView. The 'tv' can have any order; it does not
  475. // need to be sorted, and, resulting view retains its order.
  476. Query where(TableView* tv = nullptr)
  477. {
  478. return Query(m_own_ref, tv);
  479. }
  480. Query where(TableView* tv = nullptr) const
  481. {
  482. return Query(m_own_ref, tv);
  483. }
  484. // Perform queries on a Link Collection. The returned Query holds a reference to collection.
  485. Query where(const ObjList& list) const
  486. {
  487. return Query(m_own_ref, list);
  488. }
  489. Query where(const DictionaryLinkValues& dictionary_of_links) const;
  490. Query query(const std::string& query_string,
  491. const std::vector<mpark::variant<Mixed, std::vector<Mixed>>>& arguments = {}) const;
  492. Query query(const std::string& query_string, const std::vector<Mixed>& arguments) const;
  493. Query query(const std::string& query_string, const std::vector<Mixed>& arguments,
  494. const query_parser::KeyPathMapping& mapping) const;
  495. Query query(const std::string& query_string,
  496. const std::vector<mpark::variant<Mixed, std::vector<Mixed>>>& arguments,
  497. const query_parser::KeyPathMapping& mapping) const;
  498. Query query(const std::string& query_string, query_parser::Arguments& arguments,
  499. const query_parser::KeyPathMapping&) const;
  500. //@{
  501. /// WARNING: The link() and backlink() methods will alter a state on the Table object and return a reference
  502. /// to itself. Be aware if assigning the return value of link() to a variable; this might be an error!
  503. /// This is an error:
  504. /// Table& cats = owners->link(1);
  505. /// auto& dogs = owners->link(2);
  506. /// Query q = person_table->where()
  507. /// .and_query(cats.column<String>(5).equal("Fido"))
  508. /// .Or()
  509. /// .and_query(dogs.column<String>(6).equal("Meowth"));
  510. /// Instead, do this:
  511. /// Query q = owners->where()
  512. /// .and_query(person_table->link(1).column<String>(5).equal("Fido"))
  513. /// .Or()
  514. /// .and_query(person_table->link(2).column<String>(6).equal("Meowth"));
  515. /// The two calls to link() in the erroneous example will append the two values 0 and 1 to an internal vector in
  516. /// the owners table, and we end up with three references to that same table: owners, cats and dogs. They are all
  517. /// the same table, its vector has the values {0, 1}, so a query would not make any sense.
  518. LinkChain link(ColKey link_column) const;
  519. LinkChain backlink(const Table& origin, ColKey origin_col_key) const;
  520. // Conversion
  521. void schema_to_json(std::ostream& out, const std::map<std::string, std::string>& renames) const;
  522. void to_json(std::ostream& out, size_t link_depth, const std::map<std::string, std::string>& renames,
  523. JSONOutputMode output_mode = output_mode_json) const;
  524. /// \brief Compare two tables for equality.
  525. ///
  526. /// Two tables are equal if they have equal descriptors
  527. /// (`Descriptor::operator==()`) and equal contents. Equal descriptors imply
  528. /// that the two tables have the same columns in the same order. Equal
  529. /// contents means that the two tables must have the same number of rows,
  530. /// and that for each row index, the two rows must have the same values in
  531. /// each column.
  532. ///
  533. /// In mixed columns, both the value types and the values are required to be
  534. /// equal.
  535. ///
  536. /// For a particular row and column, if the two values are themselves tables
  537. /// (subtable and mixed columns) value equality implies a recursive
  538. /// invocation of `Table::operator==()`.
  539. bool operator==(const Table&) const;
  540. /// \brief Compare two tables for inequality.
  541. ///
  542. /// See operator==().
  543. bool operator!=(const Table& t) const;
  544. // Debug
  545. void verify() const;
  546. #ifdef REALM_DEBUG
  547. MemStats stats() const;
  548. #endif
  549. TableRef get_opposite_table(ColKey col_key) const;
  550. TableKey get_opposite_table_key(ColKey col_key) const;
  551. bool links_to_self(ColKey col_key) const;
  552. ColKey get_opposite_column(ColKey col_key) const;
  553. ColKey find_opposite_column(ColKey col_key) const;
  554. class DisableReplication {
  555. public:
  556. DisableReplication(Table& table) noexcept
  557. : m_table(table)
  558. , m_repl(table.m_repl)
  559. {
  560. m_table.m_repl = &g_dummy_replication;
  561. }
  562. ~DisableReplication()
  563. {
  564. m_table.m_repl = m_repl;
  565. }
  566. private:
  567. Table& m_table;
  568. Replication* const* m_repl;
  569. };
  570. private:
  571. enum LifeCycleCookie {
  572. cookie_created = 0x1234,
  573. cookie_transaction_ended = 0xcafe,
  574. cookie_initialized = 0xbeef,
  575. cookie_removed = 0xbabe,
  576. cookie_void = 0x5678,
  577. cookie_deleted = 0xdead,
  578. };
  579. // This is only used for debugging checks, so relaxed operations are fine.
  580. class AtomicLifeCycleCookie {
  581. public:
  582. void operator=(LifeCycleCookie cookie)
  583. {
  584. m_storage.store(cookie, std::memory_order_relaxed);
  585. }
  586. operator LifeCycleCookie() const
  587. {
  588. return m_storage.load(std::memory_order_relaxed);
  589. }
  590. private:
  591. std::atomic<LifeCycleCookie> m_storage = {};
  592. };
  593. mutable WrappedAllocator m_alloc;
  594. Array m_top;
  595. void update_allocator_wrapper(bool writable)
  596. {
  597. m_alloc.update_from_underlying_allocator(writable);
  598. }
  599. void refresh_allocator_wrapper() const noexcept
  600. {
  601. m_alloc.refresh_ref_translation();
  602. }
  603. Spec m_spec; // 1st slot in m_top
  604. ClusterTree m_clusters; // 3rd slot in m_top
  605. std::unique_ptr<ClusterTree> m_tombstones; // 13th slot in m_top
  606. TableKey m_key; // 4th slot in m_top
  607. Array m_index_refs; // 5th slot in m_top
  608. Array m_opposite_table; // 7th slot in m_top
  609. Array m_opposite_column; // 8th slot in m_top
  610. std::vector<std::unique_ptr<StringIndex>> m_index_accessors;
  611. ColKey m_primary_key_col;
  612. Replication* const* m_repl;
  613. static Replication* g_dummy_replication;
  614. bool m_is_frozen = false;
  615. util::Optional<bool> m_has_any_embedded_objects;
  616. TableRef m_own_ref;
  617. void batch_erase_rows(const KeyColumn& keys);
  618. size_t do_set_link(ColKey col_key, size_t row_ndx, size_t target_row_ndx);
  619. void populate_search_index(ColKey col_key);
  620. void erase_from_search_indexes(ObjKey key);
  621. void update_indexes(ObjKey key, const FieldValues& values);
  622. void clear_indexes();
  623. // Migration support
  624. void migrate_column_info();
  625. bool verify_column_keys();
  626. void migrate_indexes(ColKey pk_col_key);
  627. void migrate_subspec();
  628. void create_columns();
  629. bool migrate_objects(); // Returns true if there are no links to migrate
  630. void migrate_links();
  631. void finalize_migration(ColKey pk_col_key);
  632. void migrate_sets_and_dictionaries();
  633. /// Disable copying assignment.
  634. ///
  635. /// It could easily be implemented by calling assign(), but the
  636. /// non-checking nature of the low-level dynamically typed API
  637. /// makes it too risky to offer this feature as an
  638. /// operator.
  639. Table& operator=(const Table&) = delete;
  640. /// Create an uninitialized accessor whose lifetime is managed by Group
  641. Table(Replication* const* repl, Allocator&);
  642. void revive(Replication* const* repl, Allocator& new_allocator, bool writable);
  643. void init(ref_type top_ref, ArrayParent*, size_t ndx_in_parent, bool is_writable, bool is_frozen);
  644. void ensure_graveyard();
  645. void set_key(TableKey key);
  646. ColKey do_insert_column(ColKey col_key, DataType type, StringData name, Table* target_table,
  647. DataType key_type = DataType(0));
  648. struct InsertSubtableColumns;
  649. struct EraseSubtableColumns;
  650. struct RenameSubtableColumns;
  651. void erase_root_column(ColKey col_key);
  652. ColKey do_insert_root_column(ColKey col_key, ColumnType, StringData name, DataType key_type = DataType(0));
  653. void do_erase_root_column(ColKey col_key);
  654. void do_add_search_index(ColKey col_key, IndexType type);
  655. bool has_any_embedded_objects();
  656. void set_opposite_column(ColKey col_key, TableKey opposite_table, ColKey opposite_column);
  657. ColKey find_backlink_column(ColKey origin_col_key, TableKey origin_table) const;
  658. ColKey find_or_add_backlink_column(ColKey origin_col_key, TableKey origin_table);
  659. void do_set_primary_key_column(ColKey col_key);
  660. void validate_column_is_unique(ColKey col_key) const;
  661. ObjKey get_next_valid_key();
  662. /// Some Object IDs are generated as a tuple of the client_file_ident and a
  663. /// local sequence number. This function takes the next number in the
  664. /// sequence for the given table and returns an appropriate globally unique
  665. /// GlobalKey.
  666. GlobalKey allocate_object_id_squeezed();
  667. /// Find the local 64-bit object ID for the provided global 128-bit ID.
  668. ObjKey global_to_local_object_id_hashed(GlobalKey global_id) const;
  669. /// After a local ObjKey collision has been detected, this function may be
  670. /// called to obtain a non-colliding local ObjKey in such a way that subsequent
  671. /// calls to global_to_local_object_id() will return the correct local ObjKey
  672. /// for both \a incoming_id and \a colliding_id.
  673. ObjKey allocate_local_id_after_hash_collision(GlobalKey incoming_id, GlobalKey colliding_id,
  674. ObjKey colliding_local_id);
  675. /// Create a placeholder for a not yet existing object and return key to it
  676. Obj get_or_create_tombstone(ObjKey key, ColKey pk_col, Mixed pk_val);
  677. /// Should be called when an object is deleted
  678. void free_local_id_after_hash_collision(ObjKey key);
  679. /// Should be called when last entry is removed - or when table is cleared
  680. void free_collision_table();
  681. /// Called in the context of Group::commit() to ensure that
  682. /// attached table accessors stay valid across a commit. Please
  683. /// note that this works only for non-transactional commits. Table
  684. /// accessors obtained during a transaction are always detached
  685. /// when the transaction ends.
  686. void update_from_parent() noexcept;
  687. // Detach accessor. This recycles the Table accessor and all subordinate
  688. // accessors become invalid.
  689. void detach(LifeCycleCookie) noexcept;
  690. void fully_detach() noexcept;
  691. ColumnType get_real_column_type(ColKey col_key) const noexcept;
  692. uint64_t get_sync_file_id() const noexcept;
  693. /// Create an empty table with independent spec and return just
  694. /// the reference to the underlying memory.
  695. static ref_type create_empty_table(Allocator&, TableKey = TableKey());
  696. void nullify_links(CascadeState&);
  697. void remove_recursive(CascadeState&);
  698. Replication* get_repl() const noexcept;
  699. util::Logger* get_logger() const noexcept;
  700. void set_ndx_in_parent(size_t ndx_in_parent) noexcept;
  701. /// Refresh the part of the accessor tree that is rooted at this
  702. /// table.
  703. void refresh_accessor_tree();
  704. void refresh_index_accessors();
  705. void refresh_content_version();
  706. void flush_for_commit();
  707. bool is_cross_table_link_target() const noexcept;
  708. template <typename T>
  709. void aggregate(QueryStateBase& st, ColKey col_key) const;
  710. std::vector<ColKey> m_leaf_ndx2colkey;
  711. std::vector<ColKey::Idx> m_spec_ndx2leaf_ndx;
  712. std::vector<size_t> m_leaf_ndx2spec_ndx;
  713. Type m_table_type = Type::TopLevel;
  714. uint64_t m_in_file_version_at_transaction_boundary = 0;
  715. AtomicLifeCycleCookie m_cookie;
  716. static constexpr int top_position_for_spec = 0;
  717. static constexpr int top_position_for_columns = 1;
  718. static constexpr int top_position_for_cluster_tree = 2;
  719. static constexpr int top_position_for_key = 3;
  720. static constexpr int top_position_for_search_indexes = 4;
  721. static constexpr int top_position_for_column_key = 5;
  722. static constexpr int top_position_for_version = 6;
  723. static constexpr int top_position_for_opposite_table = 7;
  724. static constexpr int top_position_for_opposite_column = 8;
  725. static constexpr int top_position_for_sequence_number = 9;
  726. static constexpr int top_position_for_collision_map = 10;
  727. static constexpr int top_position_for_pk_col = 11;
  728. static constexpr int top_position_for_flags = 12;
  729. // flags contents: bit 0-1 - table type
  730. static constexpr int top_position_for_tombstones = 13;
  731. static constexpr int top_array_size = 14;
  732. enum { s_collision_map_lo = 0, s_collision_map_hi = 1, s_collision_map_local_id = 2, s_collision_map_num_slots };
  733. friend class _impl::TableFriend;
  734. friend class Query;
  735. template <class>
  736. friend class SimpleQuerySupport;
  737. friend class TableView;
  738. template <class T>
  739. friend class Columns;
  740. friend class Columns<StringData>;
  741. friend class ParentNode;
  742. friend struct util::serializer::SerialisationState;
  743. friend class LinkMap;
  744. friend class LinkView;
  745. friend class Group;
  746. friend class Transaction;
  747. friend class Cluster;
  748. friend class ClusterTree;
  749. friend class ColKeyIterator;
  750. friend class Obj;
  751. friend class LnkLst;
  752. friend class Dictionary;
  753. friend class IncludeDescriptor;
  754. template <class T>
  755. friend class AggregateHelper;
  756. };
  757. std::ostream& operator<<(std::ostream& o, Table::Type table_type);
  758. class ColKeyIterator {
  759. public:
  760. bool operator!=(const ColKeyIterator& other)
  761. {
  762. return m_pos != other.m_pos;
  763. }
  764. ColKeyIterator& operator++()
  765. {
  766. ++m_pos;
  767. return *this;
  768. }
  769. ColKeyIterator operator++(int)
  770. {
  771. ColKeyIterator tmp(m_table, m_pos);
  772. ++m_pos;
  773. return tmp;
  774. }
  775. ColKey operator*()
  776. {
  777. if (m_pos < m_table->get_column_count()) {
  778. REALM_ASSERT(m_table->m_spec.get_key(m_pos) == m_table->spec_ndx2colkey(m_pos));
  779. return m_table->m_spec.get_key(m_pos);
  780. }
  781. return {};
  782. }
  783. private:
  784. friend class ColKeys;
  785. ConstTableRef m_table;
  786. size_t m_pos;
  787. ColKeyIterator(const ConstTableRef& t, size_t p)
  788. : m_table(t)
  789. , m_pos(p)
  790. {
  791. }
  792. };
  793. class ColKeys {
  794. public:
  795. ColKeys(ConstTableRef&& t)
  796. : m_table(std::move(t))
  797. {
  798. }
  799. ColKeys()
  800. : m_table(nullptr)
  801. {
  802. }
  803. size_t size() const
  804. {
  805. return m_table->get_column_count();
  806. }
  807. bool empty() const
  808. {
  809. return size() == 0;
  810. }
  811. ColKey operator[](size_t p) const
  812. {
  813. return ColKeyIterator(m_table, p).operator*();
  814. }
  815. ColKeyIterator begin() const
  816. {
  817. return ColKeyIterator(m_table, 0);
  818. }
  819. ColKeyIterator end() const
  820. {
  821. return ColKeyIterator(m_table, size());
  822. }
  823. private:
  824. ConstTableRef m_table;
  825. };
  826. // Class used to collect a chain of links when building up a Query following links.
  827. // It has member functions corresponding to the ones defined on Table.
  828. class LinkChain {
  829. public:
  830. LinkChain(ConstTableRef t = {}, util::Optional<ExpressionComparisonType> type = util::none)
  831. : m_current_table(t)
  832. , m_base_table(t)
  833. , m_comparison_type(type)
  834. {
  835. }
  836. ConstTableRef get_base_table()
  837. {
  838. return m_base_table;
  839. }
  840. ConstTableRef get_current_table() const
  841. {
  842. return m_current_table;
  843. }
  844. ColKey get_current_col() const
  845. {
  846. return m_link_cols.back();
  847. }
  848. LinkChain& link(ColKey link_column)
  849. {
  850. add(link_column);
  851. return *this;
  852. }
  853. LinkChain& link(std::string col_name)
  854. {
  855. auto ck = m_current_table->get_column_key(col_name);
  856. if (!ck) {
  857. throw LogicError(ErrorCodes::InvalidProperty,
  858. util::format("'%1' has no property '%2'", m_current_table->get_class_name(), col_name));
  859. }
  860. add(ck);
  861. return *this;
  862. }
  863. LinkChain& backlink(const Table& origin, ColKey origin_col_key)
  864. {
  865. auto backlink_col_key = origin.get_opposite_column(origin_col_key);
  866. return link(backlink_col_key);
  867. }
  868. std::unique_ptr<Subexpr> column(const std::string&);
  869. std::unique_ptr<Subexpr> subquery(Query subquery);
  870. template <class T>
  871. inline Columns<T> column(ColKey col_key)
  872. {
  873. m_current_table->check_column(col_key);
  874. // Check if user-given template type equals Realm type.
  875. auto ct = col_key.get_type();
  876. if (ct == col_type_LinkList)
  877. ct = col_type_Link;
  878. if constexpr (std::is_same_v<T, Dictionary>) {
  879. if (!col_key.is_dictionary())
  880. throw LogicError(ErrorCodes::TypeMismatch, "Not a dictionary");
  881. }
  882. else {
  883. if (ct != ColumnTypeTraits<T>::column_id)
  884. throw LogicError(ErrorCodes::TypeMismatch,
  885. util::format("Expected %1 to be a %2", m_current_table->get_column_name(col_key),
  886. ColumnTypeTraits<T>::column_id));
  887. }
  888. if (std::is_same<T, Link>::value || std::is_same<T, LnkLst>::value || std::is_same<T, BackLink>::value) {
  889. m_link_cols.push_back(col_key);
  890. }
  891. return Columns<T>(col_key, m_base_table, m_link_cols, m_comparison_type);
  892. }
  893. template <class T>
  894. Columns<T> column(const Table& origin, ColKey origin_col_key)
  895. {
  896. static_assert(std::is_same<T, BackLink>::value, "");
  897. auto backlink_col_key = origin.get_opposite_column(origin_col_key);
  898. m_link_cols.push_back(backlink_col_key);
  899. return Columns<T>(backlink_col_key, m_base_table, std::move(m_link_cols));
  900. }
  901. template <class T>
  902. SubQuery<T> column(ColKey col_key, Query subquery)
  903. {
  904. static_assert(std::is_same<T, Link>::value, "A subquery must involve a link list or backlink column");
  905. return SubQuery<T>(column<T>(col_key), std::move(subquery));
  906. }
  907. template <class T>
  908. SubQuery<T> column(const Table& origin, ColKey origin_col_key, Query subquery)
  909. {
  910. static_assert(std::is_same<T, BackLink>::value, "A subquery must involve a link list or backlink column");
  911. return SubQuery<T>(column<T>(origin, origin_col_key), std::move(subquery));
  912. }
  913. template <class T>
  914. BacklinkCount<T> get_backlink_count()
  915. {
  916. return BacklinkCount<T>(m_base_table, std::move(m_link_cols));
  917. }
  918. private:
  919. friend class Table;
  920. friend class query_parser::ParserDriver;
  921. std::vector<ColKey> m_link_cols;
  922. ConstTableRef m_current_table;
  923. ConstTableRef m_base_table;
  924. util::Optional<ExpressionComparisonType> m_comparison_type;
  925. void add(ColKey ck);
  926. template <class T>
  927. std::unique_ptr<Subexpr> create_subexpr(ColKey col_key)
  928. {
  929. return std::make_unique<Columns<T>>(col_key, m_base_table, m_link_cols, m_comparison_type);
  930. }
  931. };
  932. // Implementation:
  933. inline ColKeys Table::get_column_keys() const
  934. {
  935. return ColKeys(ConstTableRef(this, m_alloc.get_instance_version()));
  936. }
  937. inline uint_fast64_t Table::get_content_version() const noexcept
  938. {
  939. return m_alloc.get_content_version();
  940. }
  941. inline uint_fast64_t Table::get_instance_version() const noexcept
  942. {
  943. return m_alloc.get_instance_version();
  944. }
  945. inline uint_fast64_t Table::get_storage_version(uint64_t instance_version) const
  946. {
  947. return m_alloc.get_storage_version(instance_version);
  948. }
  949. inline uint_fast64_t Table::get_storage_version() const
  950. {
  951. return m_alloc.get_storage_version();
  952. }
  953. inline TableKey Table::get_key() const noexcept
  954. {
  955. return m_key;
  956. }
  957. inline void Table::bump_storage_version() const noexcept
  958. {
  959. return m_alloc.bump_storage_version();
  960. }
  961. inline void Table::bump_content_version() const noexcept
  962. {
  963. m_alloc.bump_content_version();
  964. }
  965. inline size_t Table::get_column_count() const noexcept
  966. {
  967. return m_spec.get_public_column_count();
  968. }
  969. inline bool Table::is_embedded() const noexcept
  970. {
  971. return m_table_type == Type::Embedded;
  972. }
  973. inline bool Table::is_asymmetric() const noexcept
  974. {
  975. return m_table_type == Type::TopLevelAsymmetric;
  976. }
  977. inline Table::Type Table::get_table_type() const noexcept
  978. {
  979. return m_table_type;
  980. }
  981. inline StringData Table::get_column_name(ColKey column_key) const
  982. {
  983. auto spec_ndx = colkey2spec_ndx(column_key);
  984. REALM_ASSERT_3(spec_ndx, <, get_column_count());
  985. return m_spec.get_column_name(spec_ndx);
  986. }
  987. inline ColKey Table::get_column_key(StringData name) const noexcept
  988. {
  989. size_t spec_ndx = m_spec.get_column_index(name);
  990. if (spec_ndx == npos)
  991. return ColKey();
  992. return spec_ndx2colkey(spec_ndx);
  993. }
  994. inline ColumnType Table::get_real_column_type(ColKey col_key) const noexcept
  995. {
  996. return col_key.get_type();
  997. }
  998. inline DataType Table::get_column_type(ColKey column_key) const
  999. {
  1000. return DataType(column_key.get_type());
  1001. }
  1002. inline ColumnAttrMask Table::get_column_attr(ColKey column_key) const noexcept
  1003. {
  1004. return column_key.get_attrs();
  1005. }
  1006. inline DataType Table::get_dictionary_key_type(ColKey column_key) const noexcept
  1007. {
  1008. auto spec_ndx = colkey2spec_ndx(column_key);
  1009. REALM_ASSERT_3(spec_ndx, <, get_column_count());
  1010. return m_spec.get_dictionary_key_type(spec_ndx);
  1011. }
  1012. inline void Table::revive(Replication* const* repl, Allocator& alloc, bool writable)
  1013. {
  1014. m_alloc.switch_underlying_allocator(alloc);
  1015. m_alloc.update_from_underlying_allocator(writable);
  1016. m_repl = repl;
  1017. m_own_ref = TableRef(this, m_alloc.get_instance_version());
  1018. // since we're rebinding to a new table, we'll bump version counters
  1019. // Possible optimization: save version counters along with the table data
  1020. // and restore them from there. Should decrease amount of non-necessary
  1021. // recomputations of any queries relying on this table.
  1022. bump_content_version();
  1023. bump_storage_version();
  1024. // we assume all other accessors are detached, so we're done.
  1025. }
  1026. inline Allocator& Table::get_alloc() const
  1027. {
  1028. return m_alloc;
  1029. }
  1030. // For use by queries
  1031. template <class T>
  1032. inline Columns<T> Table::column(ColKey col_key, util::Optional<ExpressionComparisonType> cmp_type) const
  1033. {
  1034. LinkChain lc(m_own_ref, cmp_type);
  1035. return lc.column<T>(col_key);
  1036. }
  1037. template <class T>
  1038. inline Columns<T> Table::column(const Table& origin, ColKey origin_col_key) const
  1039. {
  1040. LinkChain lc(m_own_ref);
  1041. return lc.column<T>(origin, origin_col_key);
  1042. }
  1043. template <class T>
  1044. inline BacklinkCount<T> Table::get_backlink_count() const
  1045. {
  1046. return BacklinkCount<T>(this, {});
  1047. }
  1048. template <class T>
  1049. SubQuery<T> Table::column(ColKey col_key, Query subquery) const
  1050. {
  1051. LinkChain lc(m_own_ref);
  1052. return lc.column<T>(col_key, subquery);
  1053. }
  1054. template <class T>
  1055. SubQuery<T> Table::column(const Table& origin, ColKey origin_col_key, Query subquery) const
  1056. {
  1057. LinkChain lc(m_own_ref);
  1058. return lc.column<T>(origin, origin_col_key, subquery);
  1059. }
  1060. inline LinkChain Table::link(ColKey link_column) const
  1061. {
  1062. LinkChain lc(m_own_ref);
  1063. lc.add(link_column);
  1064. return lc;
  1065. }
  1066. inline LinkChain Table::backlink(const Table& origin, ColKey origin_col_key) const
  1067. {
  1068. auto backlink_col_key = origin.get_opposite_column(origin_col_key);
  1069. return link(backlink_col_key);
  1070. }
  1071. inline bool Table::is_empty() const noexcept
  1072. {
  1073. return size() == 0;
  1074. }
  1075. inline ConstTableRef Table::get_link_target(ColKey col_key) const noexcept
  1076. {
  1077. return const_cast<Table*>(this)->get_link_target(col_key);
  1078. }
  1079. inline bool Table::is_group_level() const noexcept
  1080. {
  1081. return bool(get_parent_group());
  1082. }
  1083. inline bool Table::operator!=(const Table& t) const
  1084. {
  1085. return !(*this == t); // Throws
  1086. }
  1087. inline bool Table::is_link_type(ColumnType col_type) noexcept
  1088. {
  1089. return col_type == col_type_Link || col_type == col_type_LinkList;
  1090. }
  1091. inline Replication* Table::get_repl() const noexcept
  1092. {
  1093. return *m_repl;
  1094. }
  1095. inline void Table::set_ndx_in_parent(size_t ndx_in_parent) noexcept
  1096. {
  1097. REALM_ASSERT(m_top.is_attached());
  1098. m_top.set_ndx_in_parent(ndx_in_parent);
  1099. }
  1100. inline size_t Table::colkey2spec_ndx(ColKey key) const
  1101. {
  1102. auto leaf_idx = key.get_index();
  1103. REALM_ASSERT(leaf_idx.val < m_leaf_ndx2spec_ndx.size());
  1104. return m_leaf_ndx2spec_ndx[leaf_idx.val];
  1105. }
  1106. inline ColKey Table::spec_ndx2colkey(size_t spec_ndx) const
  1107. {
  1108. REALM_ASSERT(spec_ndx < m_spec_ndx2leaf_ndx.size());
  1109. return m_leaf_ndx2colkey[m_spec_ndx2leaf_ndx[spec_ndx].val];
  1110. }
  1111. inline size_t Table::leaf_ndx2spec_ndx(ColKey::Idx leaf_ndx) const
  1112. {
  1113. REALM_ASSERT(leaf_ndx.val < m_leaf_ndx2colkey.size());
  1114. return m_leaf_ndx2spec_ndx[leaf_ndx.val];
  1115. }
  1116. inline ColKey::Idx Table::spec_ndx2leaf_ndx(size_t spec_ndx) const
  1117. {
  1118. REALM_ASSERT(spec_ndx < m_spec_ndx2leaf_ndx.size());
  1119. return m_spec_ndx2leaf_ndx[spec_ndx];
  1120. }
  1121. inline ColKey Table::leaf_ndx2colkey(ColKey::Idx leaf_ndx) const
  1122. {
  1123. // this may be called with leaf indicies outside of the table. This can happen
  1124. // when a column is removed from the mapping, but space for it is still reserved
  1125. // at leaf level. Operations on Cluster and ClusterTree which walks the columns
  1126. // based on leaf indicies may ask for colkeys which are no longer valid.
  1127. if (leaf_ndx.val < m_leaf_ndx2spec_ndx.size())
  1128. return m_leaf_ndx2colkey[leaf_ndx.val];
  1129. else
  1130. return ColKey();
  1131. }
  1132. bool inline Table::valid_column(ColKey col_key) const noexcept
  1133. {
  1134. if (col_key == ColKey())
  1135. return false;
  1136. ColKey::Idx leaf_idx = col_key.get_index();
  1137. if (leaf_idx.val >= m_leaf_ndx2colkey.size())
  1138. return false;
  1139. return col_key == m_leaf_ndx2colkey[leaf_idx.val];
  1140. }
  1141. // The purpose of this class is to give internal access to some, but
  1142. // not all of the non-public parts of the Table class.
  1143. class _impl::TableFriend {
  1144. public:
  1145. static Spec& get_spec(Table& table) noexcept
  1146. {
  1147. return table.m_spec;
  1148. }
  1149. static const Spec& get_spec(const Table& table) noexcept
  1150. {
  1151. return table.m_spec;
  1152. }
  1153. static TableRef get_opposite_link_table(const Table& table, ColKey col_key);
  1154. static Group* get_parent_group(const Table& table) noexcept
  1155. {
  1156. return table.get_parent_group();
  1157. }
  1158. static void remove_recursive(Table& table, CascadeState& rows)
  1159. {
  1160. table.remove_recursive(rows); // Throws
  1161. }
  1162. static void batch_erase_objects(Table& table, std::vector<ObjKey>& keys)
  1163. {
  1164. table.batch_erase_objects(keys); // Throws
  1165. }
  1166. static void batch_erase_rows(Table& table, const KeyColumn& keys)
  1167. {
  1168. table.batch_erase_rows(keys); // Throws
  1169. }
  1170. static ObjKey global_to_local_object_id_hashed(const Table& table, GlobalKey global_id)
  1171. {
  1172. return table.global_to_local_object_id_hashed(global_id);
  1173. }
  1174. };
  1175. } // namespace realm
  1176. #endif // REALM_TABLE_HPP