Skip to content

Commit

Permalink
finished section 3
Browse files Browse the repository at this point in the history
  • Loading branch information
caquillo07 committed Sep 17, 2023
1 parent f687bfc commit d71eb88
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea
cmake-build-debug
cmake-build-debug
build
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
run:
mkdir -p build
clang -Wall *.c -o ./build/db && ./build/db
151 changes: 138 additions & 13 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>

#define sizeOfAttribute(Struct, Attribute) sizeof(((Struct *)0)->Attribute );

typedef struct {
char *buffer;
ssize_t buffer_length;
ssize_t input_length;
} InputBuffer;

typedef enum {
EXECUTE_SUCCESS,
EXECUTE_TABLE_FULL,
} ExecuteResult;

typedef enum {
META_COMMAND_SUCCESS,
META_COMMAND_UNRECOGNIZED_COMMAND,
Expand All @@ -17,27 +25,106 @@ typedef enum {
typedef enum {
PREPARE_SUCCESS,
PREPARE_UNRECOGNIZED_STATEMENT,
PREPARE_SYNTAX_ERROR,
} PrepareResult;

typedef enum {
STATEMENT_INSERT,
STATEMENT_SELECT,
} StatementType;

#define COLUMN_USERNAME_SIZE 32
#define COLUMN_EMAIL_SIZE 255
typedef struct {
uint32_t id;
char username[COLUMN_USERNAME_SIZE];
char email[COLUMN_EMAIL_SIZE];
} Row;

const uint32_t ID_SIZE = sizeOfAttribute(Row, id);
const uint32_t USERNAME_SIZE = sizeOfAttribute(Row, username);
const uint32_t EMAIL_SIZE = sizeOfAttribute(Row, email);
const uint32_t ID_OFFSET = 0;
const uint32_t USERNAME_OFFSET = ID_OFFSET + ID_SIZE;
const uint32_t EMAIL_OFFSET = USERNAME_OFFSET + USERNAME_SIZE;
const uint32_t ROW_SIZE = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;

#define TABLE_MAX_PAGES 100
const uint32_t PAGE_SIZE = 4096;
const uint32_t ROWS_PER_PAGE = PAGE_SIZE / ROW_SIZE;
const uint32_t TABLE_MAX_ROWS = ROWS_PER_PAGE * TABLE_MAX_PAGES;

typedef struct {
uint32_t numRows;
void *pages[TABLE_MAX_PAGES];
} Table;

typedef struct {
StatementType type;
Row rowToInsert; // only used by insert statement
} Statement;

void serializeRow(Row *source, void *destination) {
memcpy(destination + ID_OFFSET, &(source->id), ID_SIZE);
memcpy(destination + USERNAME_OFFSET, &(source->username), USERNAME_SIZE);
memcpy(destination + EMAIL_OFFSET, &(source->email), EMAIL_SIZE);
}

void deserializeRow(void *source, Row *destination) {
memcpy(&(destination->id), source + ID_OFFSET, ID_SIZE);
memcpy(&(destination->username), source + USERNAME_OFFSET, USERNAME_SIZE);
memcpy(&(destination->email), source + EMAIL_OFFSET, EMAIL_SIZE);
}

void printRow(Row* row) {
printf("(%d, %s, %s)\n", row->id, row->username, row->email);
}

// returns a pointer to the row requested. This is used to know where to
// read/write in memory for a particular row.
void *rowSlot(Table *table, uint32_t rowNum) {
uint32_t pageNum = rowNum / ROWS_PER_PAGE;
void *page = table->pages[pageNum];
if (page == NULL) {
// Allocate memory only when we try to access page
page = table->pages[pageNum] = malloc(PAGE_SIZE);
}
uint32_t rowOffset = rowNum % ROWS_PER_PAGE;
uint32_t byteOffset = rowOffset * ROW_SIZE;
return page + byteOffset;
}

InputBuffer *newInputBuffer() {
InputBuffer *inputBuffer = (InputBuffer *) malloc(sizeof(InputBuffer));
*inputBuffer = (InputBuffer) {
.buffer = NULL,
.buffer_length= 0,
.input_length = 0,
.buffer = NULL,
.buffer_length= 0,
.input_length = 0,
};
return inputBuffer;
}

Table *newTable() {
Table *table = (Table *) malloc(sizeof(Table));
table->numRows = 0;
for (uint32_t i = 0; i < TABLE_MAX_PAGES; i++) {
table->pages[i] = NULL;
}
return table;
}

void freeTable(Table *table) {

// here tables->pages[i] will return NULL and thus exit the for loop
// once we run out of stuff to free.
//
// Does this hold once the table is full?
for (int i = 0; table->pages[i]; ++i) {
free(table->pages[i]);
}
free(table);
}

void printPrompt() {
printf("db > ");
}
Expand All @@ -59,8 +146,10 @@ void closeInputBuffer(InputBuffer *inputBuffer) {
free(inputBuffer);
}

MetaCommandResult doMetaCommand(InputBuffer *inputBuffer) {
MetaCommandResult doMetaCommand(InputBuffer *inputBuffer, Table* table) {
if (strcmp(inputBuffer->buffer, ".exit") == 0) {
closeInputBuffer(inputBuffer);
freeTable(table);
exit(EXIT_SUCCESS);
}
return META_COMMAND_UNRECOGNIZED_COMMAND;
Expand All @@ -69,6 +158,16 @@ MetaCommandResult doMetaCommand(InputBuffer *inputBuffer) {
PrepareResult prepareStatement(InputBuffer *inputBuffer, Statement *statement) {
if (strncmp(inputBuffer->buffer, "insert", 6) == 0) {
statement->type = STATEMENT_INSERT;
int argsAssigned = sscanf(
inputBuffer->buffer, "insert %d %s %s",
&(statement->rowToInsert.id),
statement->rowToInsert.username,
statement->rowToInsert.email
);
if (argsAssigned < 3) {
return PREPARE_SYNTAX_ERROR;
}

return PREPARE_SUCCESS;
}
if (strcmp(inputBuffer->buffer, "select") == 0) {
Expand All @@ -78,25 +177,43 @@ PrepareResult prepareStatement(InputBuffer *inputBuffer, Statement *statement) {
return PREPARE_UNRECOGNIZED_STATEMENT;
}

void executeStatement(Statement *statement) {
ExecuteResult executeInsert(Statement *statement, Table *table) {
if (table->numRows >= TABLE_MAX_ROWS) {
return EXECUTE_TABLE_FULL;
}
Row *rowToInsert = &(statement->rowToInsert);
serializeRow(rowToInsert, rowSlot(table, table->numRows));
table->numRows++;
return EXECUTE_SUCCESS;
}

ExecuteResult executeSelect(Statement *statement, Table *table) {
Row row;
for (uint32_t i = 0; i < table->numRows; i++) {
deserializeRow(rowSlot(table, i), &row);
printRow(&row);
}
return EXECUTE_SUCCESS;
}

ExecuteResult executeStatement(Statement *statement, Table *table) {
switch (statement->type) {
case (STATEMENT_INSERT):
printf("This is where we would do an insert.\n");
break;
return executeInsert(statement, table);
case STATEMENT_SELECT:
printf("This is where we would do a select.\n");
break;
return executeSelect(statement, table);
}
}

int main(int argc, char *argv[]) {
Table *table = newTable();
InputBuffer *inputBuffer = newInputBuffer();
while (true) {
printPrompt();
readInput(inputBuffer);

if (inputBuffer->buffer[0] == '.') {
switch (doMetaCommand(inputBuffer)) {
switch (doMetaCommand(inputBuffer, table)) {
case (META_COMMAND_SUCCESS):
continue;
case (META_COMMAND_UNRECOGNIZED_COMMAND):
Expand All @@ -111,13 +228,21 @@ int main(int argc, char *argv[]) {
switch (prepareStatement(inputBuffer, &statement)) {
case (PREPARE_SUCCESS):
break;
case PREPARE_SYNTAX_ERROR:
printf("Syntax error. Could not parse statement.\n");
continue;
case (PREPARE_UNRECOGNIZED_STATEMENT):
printf("Unrecognized keyword at start of '%s'.\n", inputBuffer->buffer);
continue;
}
executeStatement(&statement);
printf("Executed.\n");
switch (executeStatement(&statement, table)) {
case EXECUTE_SUCCESS:
printf("Executed.\n");
break;
case EXECUTE_TABLE_FULL:
printf("Error: Table is full.\n");
break;
}
}
return 0;
}

0 comments on commit d71eb88

Please sign in to comment.