aboutsummaryrefslogblamecommitdiffstats
path: root/lib/planner.ml
blob: 8127c4140670fd67048219984e1c9306935ce055 (plain) (tree)
1
2
3
4
5
6
7
8
9


                                             

                             

   
                    
           
 
                                                                      
                                                                               

















                                                                            
      




                                                                             

      
                                                                              

                             





                                                                          

                   

           


                    
           
 

                            





                                                                            
                            







                                                               

             
 
              










                                                                                                                                                                                            
           
 



                                                                    










                                                                          
      

                                                                            
                                                                                                  







                                                                               
                              




































                                                                          
   

                          





                                                                                                 

                                                                                 

































                                                                                                
module type Action = sig
  (* Names of the attributes & The tuples *)
  type tuples = string list * bytes list list

  val execute : tuples -> int
end

module Scan = struct
  open Disk

  let execute (commit : Executor.commit) locations (entity : string) =
    (*Executor.read commit locations ~filename:("schema~" ^ entity) |> function
    | Some binary -> (
        let relation =
          Result.map_error (fun _ ->
              "Failed to deserialize relation from binary format.")
          @@ Data_encoding.Binary.of_bytes Schema.Protocol.relation_encoding
               (Bytes.concat Bytes.empty binary)
        in
        match relation with
        | Ok relation ->
            let _attrs =
              List.map
                (fun (a : Schema.Protocol.attribute) ->
                  relation.name ^ "/" ^ a.name)
                relation.attributes
            in
            Executor.read commit locations ~filename:("schema~" ^ entity)
        | Error err -> failwith err)
    | None -> failwith ""
    *)
    let entities :
        (string * Executor.relational_type * string) list Executor.IntMap.t =
      Executor.StringMap.find_opt entity commit.references |> function
      | Some entities -> entities
      | None -> Executor.IntMap.empty
    in

    let content : (int64 * (string * Executor.relational_literal) list) list =
      Executor.IntMap.fold
        (fun key elems acc ->
          ( key,
            List.map
              (fun (location, type', attribute_name) ->
                ( attribute_name,
                  Executor.read_location ~hash:location locations type' ))
              elems )
          :: acc)
        entities []
    in
    content
end

module Join = struct
  open Disk

  module NestedLoop = struct
    let execute
        (left : (int64 * (string * Executor.relational_literal) list) list)
        (right : (int64 * (string * Executor.relational_literal) list) list)
        (join_clause :
          (int64 * (string * Executor.relational_literal) list)
          * (int64 * (string * Executor.relational_literal) list) ->
          bool) =
      let result = ref [] in
      List.iter
        (fun left_tuple ->
          List.iter
            (fun right_tuple ->
              if join_clause (left_tuple, right_tuple) then
                result := (left_tuple, right_tuple) :: !result)
            right)
        left;
      !result
  end

  (* open Disk
     let execute (left_attributes: bytes list) (right_attributes: bytes list) locations =
       (* Redundant operations that are already in the locations, but this is easier to implement now *)
       (* Fix this when we persist the indexes *)
       let left_computed_hashes: (int * string) list = List.mapi (fun index elem -> (index, Interop.Sha256.compute_hash elem)) left_attributes in
       let right_computed_hashes: (int * string) list = List.mapi (fun index elem -> (index, Interop.Sha256.compute_hash elem)) right_attributes in
       let references_locations_right = List.filter_map (fun (index, rhash) -> Option.map (fun (elem: Executor.Location.t) -> index, rhash, elem.references)
                                                                               @@ Executor.StringMap.find_opt rhash locations) right_computed_hashes in
       let indexes =
         List.filter_map (fun (lindex, lhash) -> Option.map (fun (rindex, rhash, _) -> lindex, rindex, lhash, rhash)
                                                 @@ List.find_opt (fun (_rindex, _rhash, references) -> List.exists ((=) lhash) references) references_locations_right) left_computed_hashes
       in List.map (fun (lindex, rindex, _, _) -> List.nth left_attributes lindex, List.nth right_attributes rindex) indexes *)
  open Disk

  let natural commit locations left_relation right_relation =
    let left_scan = Scan.execute commit locations left_relation in
    let right_scan = Scan.execute commit locations right_relation in
    let common_attributes =
      let left_attributes =
        commit.schema |> Executor.StringMap.find left_relation
      in
      let right_attributes =
        commit.schema |> Executor.StringMap.find right_relation
      in
      List.filter_map
        (fun left_attr ->
          if List.mem left_attr right_attributes then Some (fst left_attr)
          else None)
        left_attributes
    in
    let join_clause =
     fun ((_entity_id_1, left_tuple), (_entity_id_2, right_tuple)) : bool ->
      (* Check only the key name for now, not subtype, so literals must be equal for it to work *)
      let left_tuple =
        Executor.StringMap.filter (fun key _ -> List.mem key common_attributes)
        @@ Executor.StringMap.of_list left_tuple
      in
      let right_tuple =
        Executor.StringMap.filter (fun key _ -> List.mem key common_attributes)
        @@ Executor.StringMap.of_list right_tuple
      in
      left_tuple = right_tuple
    in
    NestedLoop.execute left_scan right_scan join_clause

  let nest commit locations (relation: string) =
    let parent_scan = Scan.execute commit locations relation in
    let nested_attributes =
      Executor.StringMap.find relation commit.schema
      |> List.filter (fun (_, (elem : Executor.relational_type)) ->
             match elem with Executor.Relation _ -> true | _ -> false)
    in
    let nested_scans =
      List.concat_map
        (fun (nested_relation_attr, _) ->
          Scan.execute commit locations nested_relation_attr)
        nested_attributes
    in
    List.map
      (fun (entity_id, x) ->
        ( entity_id,
          List.map
            (fun (name_attr, item) ->
              match item with
              | Executor.LRelation (nested_entity_id, nested_name_attr) ->
                  ( name_attr,
                    Executor.LRelationNested
                      ( nested_entity_id,
                        nested_name_attr,
                        List.find_map
                          (fun (iter_entity_id, iter_attrs) ->
                            if iter_entity_id = nested_entity_id then
                              Some iter_attrs
                            else None)
                          nested_scans
                        |> Option.to_list |> List.concat ) )
              | _ -> (name_attr, item))
            x ))
      parent_scan
end

module Filter = struct end

module Executor = struct
  open Disk
  open Disk.Executor
  let perform (commit : Executor.commit) (locations : Executor.locations) (command : Command.t) =
    match command with
    | State ->
       Ok ((commit, locations), Command.Schema (StringMap.to_list commit.schema))
    | Nest {relation_name;} ->
       let results = Join.nest commit locations relation_name in
       Ok ((commit, locations), Command.Read results)
    | NaturalJoin {left_relation = _; right_relation = _} ->
       Ok ((commit, locations), Nothing)
    | SpecifyRelation {relation_name; attributes} ->
       (* If it already exists under the relation name key, it will be replaced *)
       Ok (({ commit with
              schema = commit.schema
                       |> Executor.StringMap.add relation_name attributes}, locations), Nothing)
    | SequentialRead { relation_name } ->
        let relation_name = List.hd @@ String.split_on_char '/' relation_name in
        let entities : (string * Executor.relational_type * string) list Executor.IntMap.t =
          print_endline relation_name;
          Executor.StringMap.find_opt relation_name commit.references
          |> function
          | Some entities -> entities
          | None -> Executor.IntMap.empty
        in

        let content: (int64 * (string*Executor.relational_literal) list) list =
          Executor.IntMap.fold
            (fun key elems acc ->
              (key,
                List.map
                  (fun (location, type', attribute_name) ->
                    (attribute_name, Executor.read_location ~hash:location locations type'))
                  elems)
              :: acc)
            entities []
        in
        
        Ok ((commit, locations), Read content)
end