Skip to content

Commit 98714d1

Browse files
committedOct 1, 2017
Store keys in sorted order. Error on duplicate key.
1 parent 908b5d9 commit 98714d1

File tree

3 files changed

+94
-14
lines changed

3 files changed

+94
-14
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
db
22
*.db
33
_site/
4+
TODO

‎db.c

+73-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ struct InputBuffer_t {
1313
};
1414
typedef struct InputBuffer_t InputBuffer;
1515

16-
enum ExecuteResult_t { EXECUTE_SUCCESS, EXECUTE_TABLE_FULL };
16+
enum ExecuteResult_t {
17+
EXECUTE_SUCCESS,
18+
EXECUTE_DUPLICATE_KEY,
19+
EXECUTE_TABLE_FULL
20+
};
1721
typedef enum ExecuteResult_t ExecuteResult;
1822

1923
enum MetaCommandResult_t {
@@ -124,6 +128,16 @@ const uint32_t LEAF_NODE_SPACE_FOR_CELLS = PAGE_SIZE - LEAF_NODE_HEADER_SIZE;
124128
const uint32_t LEAF_NODE_MAX_CELLS =
125129
LEAF_NODE_SPACE_FOR_CELLS / LEAF_NODE_CELL_SIZE;
126130

131+
NodeType get_node_type(void* node) {
132+
uint8_t value = *((uint8_t*)node);
133+
return (NodeType)value;
134+
}
135+
136+
void set_node_type(void* node, NodeType type) {
137+
uint8_t value = type;
138+
*((uint8_t*)node) = value;
139+
}
140+
127141
uint32_t* leaf_node_num_cells(void* node) {
128142
return node + LEAF_NODE_NUM_CELLS_OFFSET;
129143
}
@@ -170,7 +184,10 @@ void deserialize_row(void* source, Row* destination) {
170184
memcpy(&(destination->email), source + EMAIL_OFFSET, EMAIL_SIZE);
171185
}
172186

173-
void initialize_leaf_node(void* node) { *leaf_node_num_cells(node) = 0; }
187+
void initialize_leaf_node(void* node) {
188+
set_node_type(node, NODE_LEAF);
189+
*leaf_node_num_cells(node) = 0;
190+
}
174191

175192
void* get_page(Pager* pager, uint32_t page_num) {
176193
if (page_num > TABLE_MAX_PAGES) {
@@ -221,19 +238,52 @@ Cursor* table_start(Table* table) {
221238
return cursor;
222239
}
223240

224-
Cursor* table_end(Table* table) {
241+
Cursor* leaf_node_find(Table* table, uint32_t page_num, uint32_t key) {
242+
void* node = get_page(table->pager, page_num);
243+
uint32_t num_cells = *leaf_node_num_cells(node);
244+
225245
Cursor* cursor = malloc(sizeof(Cursor));
226246
cursor->table = table;
227-
cursor->page_num = table->root_page_num;
228-
229-
void* root_node = get_page(table->pager, table->root_page_num);
230-
uint32_t num_cells = *leaf_node_num_cells(root_node);
231-
cursor->cell_num = num_cells;
232-
cursor->end_of_table = true;
247+
cursor->page_num = page_num;
248+
249+
// Binary search
250+
uint32_t min_index = 0;
251+
uint32_t one_past_max_index = num_cells;
252+
while (one_past_max_index != min_index) {
253+
uint32_t index = (min_index + one_past_max_index) / 2;
254+
uint32_t key_at_index = *leaf_node_key(node, index);
255+
if (key == key_at_index) {
256+
cursor->cell_num = index;
257+
return cursor;
258+
}
259+
if (key < key_at_index) {
260+
one_past_max_index = index;
261+
} else {
262+
min_index = index + 1;
263+
}
264+
}
233265

266+
cursor->cell_num = min_index;
234267
return cursor;
235268
}
236269

270+
/*
271+
Return the position of the given key.
272+
If the key is not present, return the position
273+
where it should be inserted
274+
*/
275+
Cursor* table_find(Table* table, uint32_t key) {
276+
uint32_t root_page_num = table->root_page_num;
277+
void* root_node = get_page(table->pager, root_page_num);
278+
279+
if (get_node_type(root_node) == NODE_LEAF) {
280+
return leaf_node_find(table, root_page_num, key);
281+
} else {
282+
printf("Need to implement searching an internal node\n");
283+
exit(EXIT_FAILURE);
284+
}
285+
}
286+
237287
void* cursor_value(Cursor* cursor) {
238288
uint32_t page_num = cursor->page_num;
239289
void* page = get_page(cursor->table->pager, page_num);
@@ -456,12 +506,21 @@ void leaf_node_insert(Cursor* cursor, uint32_t key, Row* value) {
456506

457507
ExecuteResult execute_insert(Statement* statement, Table* table) {
458508
void* node = get_page(table->pager, table->root_page_num);
459-
if ((*leaf_node_num_cells(node) >= LEAF_NODE_MAX_CELLS)) {
509+
uint32_t num_cells = (*leaf_node_num_cells(node));
510+
if (num_cells >= LEAF_NODE_MAX_CELLS) {
460511
return EXECUTE_TABLE_FULL;
461512
}
462513

463514
Row* row_to_insert = &(statement->row_to_insert);
464-
Cursor* cursor = table_end(table);
515+
uint32_t key_to_insert = row_to_insert->id;
516+
Cursor* cursor = table_find(table, key_to_insert);
517+
518+
if (cursor->cell_num < num_cells) {
519+
uint32_t key_at_index = *leaf_node_key(node, cursor->cell_num);
520+
if (key_at_index == key_to_insert) {
521+
return EXECUTE_DUPLICATE_KEY;
522+
}
523+
}
465524

466525
leaf_node_insert(cursor, row_to_insert->id, row_to_insert);
467526

@@ -541,6 +600,9 @@ int main(int argc, char* argv[]) {
541600
case (EXECUTE_SUCCESS):
542601
printf("Executed.\n");
543602
break;
603+
case (EXECUTE_DUPLICATE_KEY):
604+
printf("Error: Duplicate key.\n");
605+
break;
544606
case (EXECUTE_TABLE_FULL):
545607
printf("Error: Table full.\n");
546608
break;

‎spec/main_spec.rb

+20-3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,23 @@ def run_script(commands)
109109
])
110110
end
111111

112+
it 'prints an error message if there is a duplicate id' do
113+
script = [
114+
"insert 1 user1 person1@example.com",
115+
"insert 1 user1 person1@example.com",
116+
"select",
117+
".exit",
118+
]
119+
result = run_script(script)
120+
expect(result).to eq([
121+
"db > Executed.",
122+
"db > Error: Duplicate key.",
123+
"db > (1, user1, person1@example.com)",
124+
"Executed.",
125+
"db > ",
126+
])
127+
end
128+
112129
it 'allows printing out the structure of a one-node btree' do
113130
script = [3, 1, 2].map do |i|
114131
"insert #{i} user#{i} person#{i}@example.com"
@@ -123,9 +140,9 @@ def run_script(commands)
123140
"db > Executed.",
124141
"db > Tree:",
125142
"leaf (size 3)",
126-
" - 0 : 3",
127-
" - 1 : 1",
128-
" - 2 : 2",
143+
" - 0 : 1",
144+
" - 1 : 2",
145+
" - 2 : 3",
129146
"db > "
130147
])
131148
end

0 commit comments

Comments
 (0)
Please sign in to comment.