record.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef SQL_RECOVER_MODULE_RECORD_H_
  5. #define SQL_RECOVER_MODULE_RECORD_H_
  6. #include <cstdint>
  7. #include <vector>
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/sequence_checker.h"
  10. struct sqlite3_context;
  11. namespace sql {
  12. namespace recover {
  13. // The effective type of a column's value in a SQLite row.
  14. enum class ValueType {
  15. kNull,
  16. kInteger,
  17. kFloat,
  18. kText,
  19. kBlob,
  20. };
  21. class LeafPayloadReader;
  22. // Reads records from SQLite B-trees.
  23. //
  24. // Instances are designed to be reused for reading multiple records. Instances
  25. // are not thread-safe.
  26. //
  27. // A record is a list of column values. SQLite uses "manifest typing", meaning
  28. // that values don't necessarily match the column types declared in the
  29. // table/index schema.
  30. //
  31. // Reading a record is started by calling Initialize(). Afterwards,
  32. // GetValueType() can be used to validate the types of the record's values, and
  33. // ReadValue() can be used to read the values into a SQLite user-defined
  34. // function context.
  35. class RecordReader {
  36. public:
  37. struct ValueHeader {
  38. explicit ValueHeader(int64_t offset,
  39. int64_t size,
  40. ValueType type,
  41. int8_t inline_value,
  42. bool has_inline_value)
  43. : offset(offset),
  44. size(size),
  45. type(type),
  46. inline_value(inline_value),
  47. has_inline_value(has_inline_value) {}
  48. // The position of the first byte used to encode the value, in the record.
  49. int64_t offset;
  50. // The number of bytes used to encode the value.
  51. int64_t size;
  52. // The SQLite type for the value.
  53. ValueType type;
  54. // The value encoded directly in the type, if |has_inline_value| is true.
  55. int8_t inline_value;
  56. // True if |inline_value| is defined.
  57. bool has_inline_value;
  58. };
  59. // Creates an uninitialized record reader from a SQLite table B-tree.
  60. //
  61. // |payload_reader_| must outlive this instance, and should always point to
  62. // leaf pages in the same tree. |column_count| must match the number of
  63. // columns in the table's schema.
  64. //
  65. // The underlying table should not be modified while the record is
  66. // initialized.
  67. explicit RecordReader(LeafPayloadReader* payload_reader_, int column_count);
  68. ~RecordReader();
  69. RecordReader(const RecordReader&) = delete;
  70. RecordReader& operator=(const RecordReader&) = delete;
  71. // Sets up the reader for a new payload.
  72. //
  73. // The LeafPayloadReader passed to the constructor must be focused on the
  74. // page containing the payload.
  75. //
  76. // This method must complete successfully before any other method on this
  77. // class can be called.
  78. bool Initialize();
  79. // True if the last call to Initialize succeeded.
  80. bool IsInitialized() const {
  81. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  82. return value_headers_.size() == static_cast<size_t>(column_count_);
  83. }
  84. // The type of a value in the record. |column_index| is 0-based.
  85. ValueType GetValueType(int column_index) const;
  86. // Reads a value in the record into a SQLite user-defined function context.
  87. //
  88. // |column_index| is 0-based.
  89. //
  90. // The value is reported by calling a sqlite3_result_*() function on
  91. // |receiver|. SQLite's result-reporting API is documented at
  92. // https://www.sqlite.org/c3ref/result_blob.html
  93. //
  94. // Returns false if the reading value fails. This can happen if a value is
  95. // stored across overflow pages, and reading one of the overflow pages results
  96. // in an I/O error.
  97. bool ReadValue(int column_index, sqlite3_context* receiver) const;
  98. // Resets the reader.
  99. //
  100. // This method is idempotent. After it is called, IsInitialized() will return
  101. // false.
  102. void Reset();
  103. private:
  104. // Reads the record's header into |header_buffer_|.
  105. //
  106. // Returns the size of the record's header, or 0 (zero) in case of failure.
  107. // No valid record header has 0 bytes, because the record header includes at
  108. // least one varint.
  109. //
  110. // On success, |header_buffer_|'s size will be set correctly.
  111. int64_t InitializeHeaderBuffer();
  112. // Stores decoded type IDs from the record's header.
  113. std::vector<ValueHeader> value_headers_;
  114. // Stores the header of the record being read.
  115. //
  116. // The header is only used during Initialize(). This buffer is reused across
  117. // multiple Initialize() calls to reduce heap churn.
  118. std::vector<uint8_t> header_buffer_;
  119. // Brings the record's bytes from the SQLite database pages.
  120. //
  121. // Raw pointer usage is acceptable because this instance's owner is expected
  122. // to ensure that the LeafPayloadReader outlives this.
  123. const raw_ptr<LeafPayloadReader> payload_reader_;
  124. // The number of columns in the table schema. No payload should have more than
  125. // this number of columns.
  126. const int column_count_;
  127. SEQUENCE_CHECKER(sequence_checker_);
  128. };
  129. } // namespace recover
  130. } // namespace sql
  131. #endif // SQL_RECOVER_MODULE_RECORD_H_