Exercise 3: Indexing a Column With Real Duplicate Values — Possible Solution ==================================================================== THE TEST ------------------------------ db_dup.create_table('scores', [('id', 'INTEGER'), ('points', 'INTEGER')]) dup_points = [10, 20, 10, 30, 10] # points=10 appears at rows 0, 2, 4 for i, p in enumerate(dup_points): db_dup.insert('scores', [i, p]) db_dup.create_index('scores', 'points') real_matches = [[i, p] for i, p in enumerate(dup_points) if p == 10] index_matches = db_dup.select('scores', where=('points', '=', 10)) RESULT ------------------------------ real_matches -> [[0, 10], [2, 10], [4, 10]] (3 rows) index_matches -> [[4, 10]] (1 row) The two disagree: the real scan finds all three rows sharing points=10, but the index-based lookup finds only one. WHICH ROW SURVIVES, AND WHY ------------------------------ create_index builds the tree by walking table.scan_with_locations() in row-storage order and calling btree_insert(root, row[idx], location) for each one, in sequence: first row 0 (points=10, some location), then row 1 (points=20), then row 2 (points=10, a DIFFERENT location), then row 3 (points=30), then row 4 (points=10, yet another location). btree_insert's own underlying insert_into_node has, since Chapter 6, always treated a repeated key as an UPDATE: if i < len(node.keys) and node.keys[i] == key: node.values[i] = value return None Each time btree_insert encounters key=10 again (at row 2, then again at row 4), it doesn't add a second entry -- it OVERWRITES whatever location was previously stored under that same key with the new row's own location. By the time all five rows have been processed, the key 10 in the tree points at whichever row was processed LAST among the three sharing that value -- row 4, the highest index, since insertion happens in scan order (0, 1, 2, 3, 4) and each later duplicate simply replaces the earlier one's own stored location. Rows 0 and 2 are still completely, correctly present in the real heap table -- they were never deleted or corrupted -- they're just no longer FINDABLE through this particular index, because the index only ever kept a pointer to the most recently processed row sharing that key. WHY THIS WORKS AS AN ANSWER ------------------------------ This confirms the "last one wins" behavior isn't random or implementation-dependent -- it's a direct, predictable consequence of processing rows in a fixed, known order (scan order) through an insert operation that's always defined to overwrite on a repeated key. Given the same input data and the same scan order, this same result (row 4 surviving) would be reproduced identically every time -- it's deterministic, just not what a naive user might expect from "an index on a column," which is exactly why this chapter frames it as an honest, stated limitation of this course's own simplified B-tree, rather than something to silently paper over.