TestSqlHashIndex.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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::Heap& heap);
  118. void insert_and_get_to_and_from_hash_index(int num_keys);
  119. void insert_into_and_scan_hash_index(int num_keys);
  120. NonnullRefPtr<SQL::HashIndex> setup_hash_index(SQL::Heap& heap)
  121. {
  122. SQL::TupleDescriptor tuple_descriptor;
  123. tuple_descriptor.append({ "key_value", SQL::SQLType::Integer, SQL::Order::Ascending });
  124. tuple_descriptor.append({ "text_value", SQL::SQLType::Text, SQL::Order::Ascending });
  125. auto directory_pointer = heap.user_value(0);
  126. if (!directory_pointer) {
  127. directory_pointer = heap.new_record_pointer();
  128. heap.set_user_value(0, directory_pointer);
  129. }
  130. auto hash_index = SQL::HashIndex::construct(heap, 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("test.db"); });
  136. {
  137. auto heap = SQL::Heap::construct("test.db");
  138. auto hash_index = setup_hash_index(heap);
  139. for (auto ix = 0; ix < num_keys; ix++) {
  140. SQL::Key k(hash_index->descriptor());
  141. k[0] = keys[ix];
  142. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  143. k.set_pointer(pointers[ix]);
  144. hash_index->insert(k);
  145. }
  146. #ifdef LIST_HASH_INDEX
  147. hash_index->list_hash();
  148. #endif
  149. }
  150. {
  151. auto heap = SQL::Heap::construct("test.db");
  152. auto hash_index = setup_hash_index(heap);
  153. for (auto ix = 0; ix < num_keys; ix++) {
  154. SQL::Key k(hash_index->descriptor());
  155. k[0] = keys[ix];
  156. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  157. auto pointer_opt = hash_index->get(k);
  158. EXPECT(pointer_opt.has_value());
  159. EXPECT_EQ(pointer_opt.value(), pointers[ix]);
  160. }
  161. }
  162. }
  163. TEST_CASE(hash_index_one_key)
  164. {
  165. insert_and_get_to_and_from_hash_index(1);
  166. }
  167. TEST_CASE(hash_index_four_keys)
  168. {
  169. insert_and_get_to_and_from_hash_index(4);
  170. }
  171. TEST_CASE(hash_index_five_keys)
  172. {
  173. insert_and_get_to_and_from_hash_index(5);
  174. }
  175. TEST_CASE(hash_index_10_keys)
  176. {
  177. insert_and_get_to_and_from_hash_index(10);
  178. }
  179. TEST_CASE(hash_index_13_keys)
  180. {
  181. insert_and_get_to_and_from_hash_index(13);
  182. }
  183. TEST_CASE(hash_index_20_keys)
  184. {
  185. insert_and_get_to_and_from_hash_index(20);
  186. }
  187. TEST_CASE(hash_index_25_keys)
  188. {
  189. insert_and_get_to_and_from_hash_index(25);
  190. }
  191. TEST_CASE(hash_index_30_keys)
  192. {
  193. insert_and_get_to_and_from_hash_index(30);
  194. }
  195. TEST_CASE(hash_index_35_keys)
  196. {
  197. insert_and_get_to_and_from_hash_index(35);
  198. }
  199. TEST_CASE(hash_index_40_keys)
  200. {
  201. insert_and_get_to_and_from_hash_index(40);
  202. }
  203. TEST_CASE(hash_index_45_keys)
  204. {
  205. insert_and_get_to_and_from_hash_index(45);
  206. }
  207. TEST_CASE(hash_index_50_keys)
  208. {
  209. insert_and_get_to_and_from_hash_index(50);
  210. }
  211. void insert_into_and_scan_hash_index(int num_keys)
  212. {
  213. ScopeGuard guard([]() { unlink("test.db"); });
  214. {
  215. auto heap = SQL::Heap::construct("test.db");
  216. auto hash_index = setup_hash_index(heap);
  217. for (auto ix = 0; ix < num_keys; ix++) {
  218. SQL::Key k(hash_index->descriptor());
  219. k[0] = keys[ix];
  220. k[1] = String::formatted("The key value is {} and the pointer is {}", keys[ix], pointers[ix]);
  221. k.set_pointer(pointers[ix]);
  222. hash_index->insert(k);
  223. }
  224. #ifdef LIST_HASH_INDEX
  225. hash_index->list_hash();
  226. #endif
  227. }
  228. {
  229. auto heap = SQL::Heap::construct("test.db");
  230. auto hash_index = setup_hash_index(heap);
  231. Vector<bool> found;
  232. for (auto ix = 0; ix < num_keys; ix++) {
  233. found.append(false);
  234. }
  235. int count = 0;
  236. for (auto iter = hash_index->begin(); !iter.is_end(); iter++, count++) {
  237. auto key = (*iter);
  238. auto key_value = (int)key[0];
  239. for (auto ix = 0; ix < num_keys; ix++) {
  240. if (keys[ix] == key_value) {
  241. EXPECT_EQ(key.pointer(), pointers[ix]);
  242. if (found[ix])
  243. FAIL(String::formatted("Key {}, index {} already found previously", key_value, ix));
  244. found[ix] = true;
  245. break;
  246. }
  247. }
  248. }
  249. #ifdef LIST_HASH_INDEX
  250. hash_index->list_hash();
  251. #endif
  252. EXPECT_EQ(count, num_keys);
  253. for (auto ix = 0; ix < num_keys; ix++) {
  254. if (!found[ix])
  255. FAIL(String::formatted("Key {}, index {} not found", keys[ix], ix));
  256. }
  257. }
  258. }
  259. TEST_CASE(hash_index_scan_one_key)
  260. {
  261. insert_into_and_scan_hash_index(1);
  262. }
  263. TEST_CASE(hash_index_scan_four_keys)
  264. {
  265. insert_into_and_scan_hash_index(4);
  266. }
  267. TEST_CASE(hash_index_scan_five_keys)
  268. {
  269. insert_into_and_scan_hash_index(5);
  270. }
  271. TEST_CASE(hash_index_scan_10_keys)
  272. {
  273. insert_into_and_scan_hash_index(10);
  274. }
  275. TEST_CASE(hash_index_scan_15_keys)
  276. {
  277. insert_into_and_scan_hash_index(15);
  278. }
  279. TEST_CASE(hash_index_scan_20_keys)
  280. {
  281. insert_into_and_scan_hash_index(20);
  282. }
  283. TEST_CASE(hash_index_scan_30_keys)
  284. {
  285. insert_into_and_scan_hash_index(30);
  286. }
  287. TEST_CASE(hash_index_scan_40_keys)
  288. {
  289. insert_into_and_scan_hash_index(40);
  290. }
  291. TEST_CASE(hash_index_scan_50_keys)
  292. {
  293. insert_into_and_scan_hash_index(50);
  294. }