Currently we have a byteArray to which we append data directly but in an actual database we would have B-trees to help with that we will create a cursor abstaraction that will help us find the page and byte_offset and advance i case of insert
from Pager import *
class Cursor:
def __init__(self,table,row_num,end_of_table):
self.table=table
self.row_num=row_num
self.end_of_table=end_of_table
def value(self):
page_num=self.row_num//ROWS_PER_PAGE
page=self.table.pager.get_page(page_num)
row_offset = self.row_num % ROWS_PER_PAGE
byte_offset = row_offset * ROW_SIZE
return page , byte_offset
def advance(self):
self.row_num+=1
if self.row_num >= self.table.num_rows:
self.end_of_table=True
The value func is straight forward it returns the page and byte_offset like the original table row_slot function.
The advance function increments the row_num, we will run this after every insert
There fore we now need to make some more changes to our table to remove redundancy
class Table:
def __init__(self,pager,num_rows):
self.pager=pager
self.num_rows=num_rows
def table_start(self):
is_end = (self.num_rows ==0)
return Cursor(table=self,row_num=0,end_of_table=is_end)
def table_end(self):
return Cursor(table=self,row_num=self.num_rows,end_of_table=True)
Now instead of the row_slot function we have the table start and table end function these set the cursor to the beginning or the end of the table respectively, one reason for this is that our cursor will now take care of maintaining the position of the elements, but it will make more sense once we update the execute funcs
def execute_insert(statement, table):
if table.num_rows >= TABLE_MAX_ROWS:
return "TABLE_FULL"
cursor=table.table_end()
page, offset = cursor.value()
serialize_row(statement["data"], page, offset)
table.num_rows += 1
return "SUCCESS"
For the insert command we first find the table end find the page and offset append the data to the byte_array(remember a bytearray is a page) and add a row to the total rows, then finally return.
def execute_select(table):
cursor= table.table_start()
while not cursor.end_of_table:
page, offset = cursor.value()
row = deserialize_row(page, offset)
print(f"({row[0]}, {row[1]}, {row[2]})")
cursor.advance()
return "SUCCESS"
For the select statement we want to start from the beginning and read every line, for this we go to the table start and iterate over each item until cursor hits the end of the table