Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ setup.log

# Local OPAM switch
_opam/

# db file
*.db
12 changes: 11 additions & 1 deletion bin/main.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
let () =
Printf.printf "*********SQCaml*********\n\r";
SQCaml.Repl.start ()
let db_dir =
if Array.length Sys.argv >= 2 then
Sys.argv.(1)
else
"sqcaml.db"
in
let db = SQCaml.Db_session.open_db db_dir in
try SQCaml.Repl.start db
with exn ->
SQCaml.Db_session.close_db db;
raise exn
10 changes: 1 addition & 9 deletions lib/ast/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@ type binop_t =
| Comp
[@@deriving show]

(* type column_types = *)
(* | Int_col *)
(* | Float_col *)
(* | String_col *)
(* | Bool_col *)
(* [@@deriving show] *)

(** Our Abstract Syntax Tree for interpreter, hooray! *)
type expr =
| Int of int
Expand Down Expand Up @@ -48,10 +41,9 @@ type statement =
type meta_command =
| Help
| Exit
| Tree
| Unk_mcmd of string
[@@deriving show]

type top_level =
| Statement of statement
| Meta_command of meta_command
[@@deriving show]
54 changes: 37 additions & 17 deletions lib/ast/insert.ml
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
(* abstraction to make a module for preparing and executing insert statement*)

type t = {
table : Table.t;
(* tree : Btree.t; *)
fields : string list;
values : Constant.t list;
}
[@@deriving show]

(* HACKY for now, new table each time *)
let make (tablename : string) (fields : string list) (values : Constant.t list)
: t =
{ table = Table.create_table ~id:777 ~table_name:tablename; fields; values }
(* let make (tablename : string) (fields : string list) (values : Constant.t list) *)
let make (fields : string list) (values : Constant.t list) : t =
(* { table = Table.create_table ~id:777 ~table_name:tablename; fields; values } *)
{ fields; values }

let execute_insert (preped_insert : t) : string =
(* let new_table = Table.add_row ~table:temp_table ~row:new_row in *)
let new_fields =
List.fold_left
(fun acc l ->
match l with
| Constant.ConstStr s -> acc ^ " " ^ s
| Constant.ConstInt d -> acc ^ " " ^ Int.to_string (Int32.to_int d))
"" preped_insert.values
let execute_insert (db : Db_session.t) (preped_insert : t) : string =
(* serialize the insert to a page*)
let new_row =
match preped_insert.values with
| [ id; stop; rail ] ->
Table.make_row
~id:(Int32.to_int (Constant.to_int id))
~stop_name:(Constant.to_str stop) ~rail_line:(Constant.to_str rail)
| _ -> failwith "Wrong amount of args passed"
in
(* new_fields *)
"Inserted" ^ new_fields ^ " into " ^ preped_insert.table.table_name
let cursor = Cursor.tree_end db.index in

(* Printf.printf "Inserted %d %s %s into Table %d" id stop_name rail_name *)
(* preped_insert.table.table_name *)
(* check to guard capacity*)
let leaf = Btree.get_node db.index cursor.page_num in
if leaf.cur_size >= leaf.capacity then
failwith "HELP! please implement splitting plz."
else
(* serialize the page and write to a block! *)
let page =
Table.serialize_to_page new_row
~block_size:(File_manager.get_blocksize db.file_manager)
in
let row_block =
Storage_manager.append ~storage_m:db.storage_manager ~page
in
(* block num where we want to write to disk!!*)
let row_block_num = Page.Block.block_num row_block in
let key = Keys.Integer (Int32.of_int new_row.id) in
(* getting and writing our tree node to disk FINALLY*)
Cursor.leaf_node_insert cursor key row_block_num;

(* printing the res *)
let res = "Inserted " ^ new_row.stop_name ^ " " ^ new_row.rail_line ^ " " in
res
4 changes: 2 additions & 2 deletions lib/ast/select.ml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ type t = {
let make (fields : string list) (tablename : string) : t =
{ table = Table.create_table ~id:777 ~table_name:tablename; fields }

let execute_select (preped_select : t) : string =
let execute_select (_ : Db_session.t) (preped_select : t) : string =
let selected_fields =
List.fold_left
(fun acc l ->
match l with
| "id" -> acc ^ " 1"
(* | "id" -> acc ^ " 1" *)
| "stop_name" -> acc ^ "englewood"
| "rail_line" -> acc ^ " G"
| _ -> "not a valid field in the table")
Expand Down
93 changes: 69 additions & 24 deletions lib/ast/table.ml
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,86 @@ type t = {
}
[@@deriving show]

(* hard coding rows for serialization *)
let stop_name_size = 64
let rail_line_size = 64
let id_offset = 0
let stop_offset = id_offset + 4
let rail_offset = stop_name_size + stop_offset
let row_size = 4 + stop_name_size + rail_line_size
let make_row ~id ~stop_name ~rail_line : row_t = { id; stop_name; rail_line }

let create_table ~(id : int) ~(table_name : string) : t =
{ table_id = id; table_name; table_fields = []; rows = [] }
let rows = [] in
{ table_id = id; table_name; table_fields = []; rows }

(* let open_table ~(table_name : string) : t = *)
(* match table_name with *)
(* | *)

let already_in_table ~(table : t) ~(row : row_t) : bool =
(* List.mem row table.rows *)
let rec search (table_rows : row_t list) (id : int) : bool =
match table_rows with
| [] -> false
| h :: tail ->
if h.id = id then
true
else
search tail id
in
search table.rows row.id
(* let already_in_table ~(table : t) ~(row : row_t) : bool = *)
(* (* List.mem row table.rows *) *)
(* let rec search (table_rows : row_t list) (id : int) : bool = *)
(* match table_rows with *)
(* | [] -> false *)
(* | h :: tail -> *)
(* if h.id = id then *)
(* true *)
(* else *)
(* search tail id *)
(* in *)
(* search table.rows row.id *)

(* currently this is a bit functional in it's nature
always returning a new table rather than adjusting the existing one.
May want to consider changing rows to be mutable, or need to consider disk
writes here - TBD *)
let add_row ~(table : t) ~(row : row_t) : t =
if already_in_table ~table ~row then
table
(* let add_row ~(table : t) ~(row : row_t) : t = *)
(* if already_in_table ~table ~row then *)
(* table *)
(* else *)
(* (* let new_row_list = List.fold_left (fun acc l -> acc :: l) table.rows [row] in *) *)
(* let new_row_list = table.rows @ [ row ] in *)
(* { *)
(* table_id = table.table_id; *)
(* table_name = table.table_name; *)
(* table_fields = table.table_fields; *)
(* rows = new_row_list; *)
(* num_rows = List.length new_row_list; *)
(* } *)

let pad_fixed_size (size : int) (s : string) : string =
if String.length s > size then
failwith
(Printf.sprintf "String too long.\nGreater than input size of %d" size)
else
(* let new_row_list = List.fold_left (fun acc l -> acc :: l) table.rows [row] in *)
let new_row_list = table.rows @ [ row ] in
{
table_id = table.table_id;
table_name = table.table_name;
table_fields = table.table_fields;
rows = new_row_list;
}
s ^ String.make (size - String.length s) '\000'

let trim_null (s : string) : string =
match String.index_opt s '\000' with
| None -> s
| Some thing -> String.sub s 0 thing

let serialize_to_page (row : row_t) ~(block_size : int) : Page.Page.t =
if row_size > block_size then
failwith "Row doesn't fit into page";

let page = Page.Page.make ~block_size in
(* serialize id, stop name, then rail name *)
Page.Page.set_int32 page id_offset (Int32.of_int row.id);
Page.Page.set_string_raw page stop_offset
(pad_fixed_size stop_name_size row.stop_name);
Page.Page.set_string_raw page rail_offset
(pad_fixed_size rail_line_size row.rail_line);
page

let deserialize_from_page (page : Page.Page.t) : row_t =
(* get the id, stop name, and rail name from the Int32 offsets*)
let id = Int32.to_int (Page.Page.get_int32 page id_offset) in
let stop_name =
trim_null (Page.Page.get_string_raw page stop_offset stop_name_size)
in
let rail_line =
trim_null (Page.Page.get_string_raw page rail_offset rail_line_size)
in
{ id; stop_name; rail_line }
57 changes: 57 additions & 0 deletions lib/btree/btree.ml
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,60 @@ let get_node (btree : t) (p : int) : Nodes.t =
Storage_manager.get_block ~storage_m:btree.storage_m ~block_num:p
in
deserialize page btree.key block_size

[@@@warning "-32"]

let empty_node (btree : t) : Nodes.t =
let block_size = File_manager.get_blocksize btree.storage_m.file_manager in
let key_type = btree.key in
let capacity = get_num_keys block_size key_type in
{
Nodes.node_t = Leaf;
Nodes.parent = 0;
Nodes.cur_size = 0;
Nodes.keys = Array.init capacity (fun _ -> Keys.empty_key key_type);
Nodes.pointers = Array.init (capacity + 1) (fun _ -> unused_pointer_serial);
Nodes.capacity;
Nodes.key_type;
}

(* Make an empty btree initialized to disk *)
let create (storage_m : Storage_manager.t) (key_type : Keys.t) : t =
let block_size = File_manager.get_blocksize storage_m.file_manager in
let meta = Storage_manager.get_head_page ~storage_manager:storage_m in
Page.Page.set_int32 meta 4 (Int32.of_int 1);
Storage_manager.update_block_num ~storage_m ~block_num:0 ~page:meta;
let capacity = get_num_keys block_size key_type in
let root_node =
{
Nodes.node_t = Leaf;
Nodes.parent = 0;
Nodes.cur_size = 0;
Nodes.keys = Array.init capacity (fun _ -> Keys.empty_key key_type);
Nodes.pointers =
Array.init (capacity + 1) (fun _ -> unused_pointer_serial);
Nodes.capacity;
Nodes.key_type;
}
in
let root_page = serialize root_node block_size in
let _ = Storage_manager.append ~storage_m ~page:root_page in
{ storage_m; key = key_type; root = root_node; root_num = 1 }

let open_btree (storage_m : Storage_manager.t) (key_type : Keys.t) : t =
let block_size = File_manager.get_blocksize storage_m.file_manager in
let meta = Storage_manager.get_head_page ~storage_manager:storage_m in
let root_num = Int32.to_int (Page.Page.get_int32 meta 4) in
if root_num = 0 then
(* create btree instead *)
create storage_m key_type
else
let root_page = Storage_manager.get_block ~storage_m ~block_num:root_num in
let root_node = deserialize root_page key_type block_size in
{ storage_m; key = key_type; root = root_node; root_num }

[@@@warning "-32"]

let print_tree (tree : t) : string =
let root_node = get_node tree tree.root_num in
Nodes.print_leaf_node root_node
13 changes: 12 additions & 1 deletion lib/btree/btree.mli
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
type t
type t = {
storage_m : Storage_manager.t; (* file used to store to disk *)
key : Keys.t;
mutable root : Nodes.t;
mutable root_num : int;
}
(** Struct for the B+ Tree *)

val serialize : Nodes.t -> int -> Page.Page.t
Expand All @@ -22,3 +27,9 @@ val write_node_append : t -> Nodes.t -> int
val get_node : t -> int -> Nodes.t
(** Get a block from the btree [t] and deserializeit using the pointer [p] into
a btree node *)

val open_btree : Storage_manager.t -> Keys.t -> t
(** Opens btree given [storage manager] and [key type]. If it doesn't exist,
creates a new btree *)

val print_tree : t -> string
14 changes: 13 additions & 1 deletion lib/btree/nodes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,16 @@ let int32_to_node_t (i32 : Int32.t) : node_type =
else if i32 = internal_serial then
Internal
else
failwith "WRONG i32!"
failwith (Printf.sprintf "WRONG i32: %ld" i32)

let print_leaf_node (n : t) : string =
if n.node_t <> Leaf then
"Not a leaf node"
else
let lines =
List.init n.cur_size (fun i ->
match n.keys.(i) with
| Keys.Integer n -> Printf.sprintf "- %d\n" (Int32.to_int n)
| Keys.Varchar v -> Printf.sprintf "- %s\n" v)
in
Printf.sprintf "leaf (size %d)\n%s" n.cur_size (String.concat "" lines)
1 change: 1 addition & 0 deletions lib/btree/nodes.mli
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ type t = {

val serialize_node : node_type -> Int32.t
val int32_to_node_t : Int32.t -> node_type
val print_leaf_node : t -> string
13 changes: 13 additions & 0 deletions lib/constant.ml
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
(** Used to represent non AST plain values in SQL queries. More of help than
anything*)

exception NotIntConst
exception NotStrConst

type t =
| ConstInt of Int32.t
| ConstStr of string
[@@deriving show]

let make_int (i32 : Int32.t) : t = ConstInt i32
let make_string (str : string) : t = ConstStr str

let to_int (constint : t) : Int32.t =
match constint with
| ConstInt i32 -> i32
| ConstStr _ -> raise NotIntConst

let to_str (constint : t) : string =
match constint with
| ConstInt _ -> raise NotStrConst
| ConstStr s -> s
Loading
Loading