Printf.printf "read_record <valid table> <valid ref> foreign key\n";
Client.create_row "VBD" (make_vbd valid_ref vbd_ref vbd_uuid) vbd_ref;
let fv_list, fvs_list = Client.read_record "VM" valid_ref in
- if List.assoc "VBDs" fvs_list <> [ vbd_ref ]
- then failwith "read_record <valid table> <valid ref> 3";
+ if List.assoc "VBDs" fvs_list <> [ vbd_ref ] then begin
+ Printf.printf "fv_list = [ %s ] fvs_list = [ %s ]\n%!" (String.concat "; " (List.map (fun (k, v) -> k ^":" ^ v) fv_list)) (String.concat "; " (List.map (fun (k, v) -> k ^ ":" ^ (String.concat ", " v)) fvs_list));
+ failwith "read_record <valid table> <valid ref> 3"
+ end;
Printf.printf "read_record <valid table> <valid ref> deleted foreign key\n";
Client.delete_row "VBD" vbd_ref;
let fv_list, fvs_list = Client.read_record "VM" valid_ref in
(* non-persistent fields will have been flushed to disk anyway [since non-persistent just means dont trigger a flush
if I change]. Hence we blank non-persistent fields with a suitable empty value, depending on their type *)
let blow_away_non_persistent_fields (schema: Schema.t) db =
- Printf.printf "blow_away\n%!";
(* Generate a new row given a table schema *)
let row schema row : Row.t =
Row.fold
)
tbl acc)
x.tables KeyMap.empty in
+ (* For each of the one-to-many relationships, recompute the many end *)
+ let tables =
+ Schema.StringMap.fold
+ (fun one_tblname rels tables ->
+ List.fold_left (fun tables (one_fldname, many_tblname, many_fldname) ->
+ (* VBD.VM : Ref(VM) -> VM.VBDs : Set(Ref(VBD)) *)
+ let one_tbl = TableSet.find one_tblname tables in
+ let many_tbl = TableSet.find many_tblname tables in
+ (* Initialise all VM.VBDs = [] (otherwise VMs with no
+ VBDs may be missing a VBDs field altogether on
+ upgrade) *)
+ let many_tbl' = Table.fold
+ (fun vm row acc ->
+ let row' = Row.add many_fldname (SExpr.string_of (SExpr.Node [])) row in
+ Table.add vm row' acc)
+ many_tbl Table.empty in
+
+ (* Build up a table of VM -> VBDs *)
+
+ let vm_to_vbds = Table.fold
+ (fun vbd row acc ->
+ let vm = Row.find one_fldname row in
+ let existing = if Schema.StringMap.mem vm acc then Schema.StringMap.find vm acc else [] in
+ Schema.StringMap.add vm (vbd :: existing) acc)
+ one_tbl Schema.StringMap.empty in
+ let many_tbl'' = Schema.StringMap.fold
+ (fun vm vbds acc ->
+ if not(Table.mem vm acc)
+ then acc
+ else
+ let row = Table.find vm acc in
+ let vbds' = SExpr.string_of (SExpr.Node (List.map (fun x -> SExpr.String x) vbds)) in
+ let row' = Row.add many_fldname vbds' row in
+ Table.add vm row' acc)
+ vm_to_vbds many_tbl' in
+ TableSet.add many_tblname many_tbl'' tables)
+ tables rels)
+ x.schema.Schema.one_to_many
+ x.tables in
- { x with keymap = keymap }
+ { x with keymap = keymap; tables = tables }
let table_of_ref rf db = fst (KeyMap.find (Ref rf) db.keymap)
[] -> acc
| (Datamodel_types.Field f)::fs -> flatten_fields fs (f::acc)
| (Datamodel_types.Namespace (_,internal_fs))::fs -> flatten_fields fs (flatten_fields internal_fs acc) in
- let column f = {
- Column.name = Escaping.escape_id f.Datamodel_types.full_name;
- persistent = f.Datamodel_types.field_persist;
- empty = Datamodel_values.gen_empty_db_val f.Datamodel_types.ty;
- (* NB Set(Ref _) fields aren't allowed to have a default value specified so we hardcode one here *)
- default = begin match f.Datamodel_types.ty with
- | Datamodel_types.Set (Datamodel_types.Ref _) -> Some (SExpr.string_of (SExpr.Node []))
- | _ -> Opt.map Datamodel_values.to_db_string f.Datamodel_types.default_value
- end ;
- issetref = begin match f.Datamodel_types.ty with
+ let column f =
+ let issetref = match f.Datamodel_types.ty with
| Datamodel_types.Set (Datamodel_types.Ref _) -> true
- | _ -> false
- end ;
- } in
+ | _ -> false in
+ {
+ Column.name = Escaping.escape_id f.Datamodel_types.full_name;
+ (* NB we always regenerate Set(Ref _) fields *)
+ persistent = f.Datamodel_types.field_persist && not issetref;
+ empty = Datamodel_values.gen_empty_db_val f.Datamodel_types.ty;
+ (* NB Set(Ref _) fields aren't allowed to have a default value specified so we hardcode one here *)
+ default =
+ if issetref
+ then Some (SExpr.string_of (SExpr.Node []))
+ else Opt.map Datamodel_values.to_db_string f.Datamodel_types.default_value ;
+ issetref = issetref;
+ } in
(* We store the reference in two places for no good reason still: *)
let _ref = {