table.hpp 48 KB

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