TestSqlHashIndex.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibSQL/HashIndex.h>
  7. #include <LibSQL/Heap.h>
  8. #include <LibSQL/Meta.h>
  9. #include <LibSQL/Tuple.h>
  10. #include <LibSQL/Value.h>
  11. #include <LibTest/TestCase.h>
  12. #include <unistd.h>
  13. constexpr static int keys[] = {
  14. 39,
  15. 87,
  16. 77,
  17. 42,
  18. 98,
  19. 40,
  20. 53,
  21. 8,
  22. 37,
  23. 12,
  24. 90,
  25. 72,
  26. 73,
  27. 11,
  28. 88,
  29. 22,
  30. 10,
  31. 82,
  32. 25,
  33. 61,
  34. 97,
  35. 18,
  36. 60,
  37. 68,
  38. 21,
  39. 3,
  40. 58,
  41. 29,
  42. 13,
  43. 17,
  44. 89,
  45. 81,
  46. 16,
  47. 64,
  48. 5,
  49. 41,
  50. 36,
  51. 91,
  52. 38,
  53. 24,
  54. 32,
  55. 50,
  56. 34,
  57. 94,
  58. 49,
  59. 47,
  60. 1,
  61. 6,
  62. 44,
  63. 76,
  64. };
  65. constexpr static u32 pointers[] = {
  66. 92,
  67. 4,
  68. 50,
  69. 47,
  70. 68,
  71. 73,
  72. 24,
  73. 28,
  74. 50,
  75. 93,
  76. 60,
  77. 36,
  78. 92,
  79. 72,
  80. 53,
  81. 26,
  82. 91,
  83. 84,
  84. 25,
  85. 43,
  86. 88,
  87. 12,
  88. 62,
  89. 35,
  90. 96,
  91. 27,
  92. 96,
  93. 27,
  94. 99,
  95. 30,
  96. 21,
  97. 89,
  98. 54,
  99. 60,
  100. 37,
  101. 68,
  102. 35,
  103. 55,
  104. 80,
  105. 2,
  106. 33,
  107. 26,
  108. 93,
  109. 70,
  110. 45,
  111. 44,
  112. 3,
  113. 66,
  114. 75,
  115. 4,
  116. };
  117. NonnullRefPtr<SQL::HashIndex> setup_hash_index(SQL::Serializer&);
  118. void insert_and_get_to_and_from_hash_index(int);
  119. void insert_into_and_scan_hash_index(int);
  120. NonnullRefPtr<SQL::HashIndex> setup_hash_index(SQL::Serializer& serializer)
  121. {
  122. NonnullRefPtr<SQL::TupleDescriptor> tuple_descriptor = adopt_ref(*new SQL::TupleDescriptor);
  123. tuple_descriptor->append({ "schema", "table", "key_value", SQL::SQLType::Integer, SQL::Order::Ascending });
  124. tuple_descriptor->append({ "schema", "table", "text_value", SQL::SQLType::Text, SQL::Order::Ascending });
  125. auto directory_pointer = serializer.heap().user_value(0);
  126. if (!directory_pointer) {
  127. directory_pointer = serializer.heap().new_record_pointer();
  128. serializer.heap().set_user_value(0, directory_pointer);
  129. }
  130. auto hash_index = SQL::HashIndex::construct(serializer, tuple_descriptor, directory_pointer);
  131. return hash_index;
  132. }
  133. void insert_and_get_to_and_from_hash_index(int num_keys)
  134. {
  135. ScopeGuard guard([]() { unlink("/tmp/test.db"); });
  136. {
  137. auto heap = SQL::Heap::construct("/tmp/test.db");
  138. EXPECT(!heap->open().is_error());
  139. SQL::Serializer serializer(heap);
  140. auto hash_index = setup_hash_index(serializer);
  141. for (auto ix = 0; ix < num_keys; ix++) {
  142. SQL::Key k(hash_index->descriptor());
  143. k[0] = keys[ix];
  144. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  145. k.set_pointer(pointers[ix]);
  146. hash_index->insert(k);
  147. }
  148. #ifdef LIST_HASH_INDEX
  149. hash_index->list_hash();
  150. #endif
  151. }
  152. {
  153. auto heap = SQL::Heap::construct("/tmp/test.db");
  154. EXPECT(!heap->open().is_error());
  155. SQL::Serializer serializer(heap);
  156. auto hash_index = setup_hash_index(serializer);
  157. for (auto ix = 0; ix < num_keys; ix++) {
  158. SQL::Key k(hash_index->descriptor());
  159. k[0] = keys[ix];
  160. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  161. auto pointer_opt = hash_index->get(k);
  162. VERIFY(pointer_opt.has_value());
  163. EXPECT_EQ(pointer_opt.value(), pointers[ix]);
  164. }
  165. }
  166. }
  167. TEST_CASE(hash_index_one_key)
  168. {
  169. insert_and_get_to_and_from_hash_index(1);
  170. }
  171. TEST_CASE(hash_index_four_keys)
  172. {
  173. insert_and_get_to_and_from_hash_index(4);
  174. }
  175. TEST_CASE(hash_index_five_keys)
  176. {
  177. insert_and_get_to_and_from_hash_index(5);
  178. }
  179. TEST_CASE(hash_index_10_keys)
  180. {
  181. insert_and_get_to_and_from_hash_index(10);
  182. }
  183. TEST_CASE(hash_index_13_keys)
  184. {
  185. insert_and_get_to_and_from_hash_index(13);
  186. }
  187. TEST_CASE(hash_index_20_keys)
  188. {
  189. insert_and_get_to_and_from_hash_index(20);
  190. }
  191. TEST_CASE(hash_index_25_keys)
  192. {
  193. insert_and_get_to_and_from_hash_index(25);
  194. }
  195. TEST_CASE(hash_index_30_keys)
  196. {
  197. insert_and_get_to_and_from_hash_index(30);
  198. }
  199. TEST_CASE(hash_index_35_keys)
  200. {
  201. insert_and_get_to_and_from_hash_index(35);
  202. }
  203. TEST_CASE(hash_index_40_keys)
  204. {
  205. insert_and_get_to_and_from_hash_index(40);
  206. }
  207. TEST_CASE(hash_index_45_keys)
  208. {
  209. insert_and_get_to_and_from_hash_index(45);
  210. }
  211. TEST_CASE(hash_index_50_keys)
  212. {
  213. insert_and_get_to_and_from_hash_index(50);
  214. }
  215. void insert_into_and_scan_hash_index(int num_keys)
  216. {
  217. ScopeGuard guard([]() { unlink("/tmp/test.db"); });
  218. {
  219. auto heap = SQL::Heap::construct("/tmp/test.db");
  220. EXPECT(!heap->open().is_error());
  221. SQL::Serializer serializer(heap);
  222. auto hash_index = setup_hash_index(serializer);
  223. for (auto ix = 0; ix < num_keys; ix++) {
  224. SQL::Key k(hash_index->descriptor());
  225. k[0] = keys[ix];
  226. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  227. k.set_pointer(pointers[ix]);
  228. hash_index->insert(k);
  229. }
  230. #ifdef LIST_HASH_INDEX
  231. hash_index->list_hash();
  232. #endif
  233. }
  234. {
  235. auto heap = SQL::Heap::construct("/tmp/test.db");
  236. EXPECT(!heap->open().is_error());
  237. SQL::Serializer serializer(heap);
  238. auto hash_index = setup_hash_index(serializer);
  239. Vector<bool> found;
  240. for (auto ix = 0; ix < num_keys; ix++) {
  241. found.append(false);
  242. }
  243. int count = 0;
  244. for (auto iter = hash_index->begin(); !iter.is_end(); iter++, count++) {
  245. auto key = (*iter);
  246. auto key_value = (int)key[0];
  247. for (auto ix = 0; ix < num_keys; ix++) {
  248. if (keys[ix] == key_value) {
  249. EXPECT_EQ(key.pointer(), pointers[ix]);
  250. if (found[ix])
  251. FAIL(String::formatted("Key {}, index {} already found previously", key_value, ix));
  252. found[ix] = true;
  253. break;
  254. }
  255. }
  256. }
  257. #ifdef LIST_HASH_INDEX
  258. hash_index->list_hash();
  259. #endif
  260. EXPECT_EQ(count, num_keys);
  261. for (auto ix = 0; ix < num_keys; ix++) {
  262. if (!found[ix])
  263. FAIL(String::formatted("Key {}, index {} not found", keys[ix], ix));
  264. }
  265. }
  266. }
  267. TEST_CASE(hash_index_scan_one_key)
  268. {
  269. insert_into_and_scan_hash_index(1);
  270. }
  271. TEST_CASE(hash_index_scan_four_keys)
  272. {
  273. insert_into_and_scan_hash_index(4);
  274. }
  275. TEST_CASE(hash_index_scan_five_keys)
  276. {
  277. insert_into_and_scan_hash_index(5);
  278. }
  279. TEST_CASE(hash_index_scan_10_keys)
  280. {
  281. insert_into_and_scan_hash_index(10);
  282. }
  283. TEST_CASE(hash_index_scan_15_keys)
  284. {
  285. insert_into_and_scan_hash_index(15);
  286. }
  287. TEST_CASE(hash_index_scan_20_keys)
  288. {
  289. insert_into_and_scan_hash_index(20);
  290. }
  291. TEST_CASE(hash_index_scan_30_keys)
  292. {
  293. insert_into_and_scan_hash_index(30);
  294. }
  295. TEST_CASE(hash_index_scan_40_keys)
  296. {
  297. insert_into_and_scan_hash_index(40);
  298. }
  299. TEST_CASE(hash_index_scan_50_keys)
  300. {
  301. insert_into_and_scan_hash_index(50);
  302. }