Skip to content

Commit 315db5a

Browse files
committed
more work
1 parent b3d27f5 commit 315db5a

21 files changed

+374
-84
lines changed

.envrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake;

eopt/egraph_matcher.ml

+3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ module C = struct
7575
let list g = mk_query Ast.alist g
7676
let hash_idx g = mk_query Ast.ahashidx g
7777
let ordered_idx g = mk_query Ast.aorderedidx g
78+
let depjoin g = mk_query Ast.depjoin g
7879
let tuple g ts k = G.add g (ATuple (ts, k))
80+
let scalar g = mk_query Ast.ascalar g
81+
let scalar_name g n = scalar g { s_pred = `Name n; s_name = Name.name n }
7982
end
8083

8184
let to_annot = G.choose_exn

eopt/join_elim_tactics.ml

+77-59
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,75 @@
1-
(* open Core *)
2-
(* open Castor *)
3-
(* open Ast *)
4-
(* open Schema *)
5-
(* open Collections *)
6-
(* module P = Pred.Infix *)
7-
(* module A = Abslayout *)
8-
(* open Match.Query *)
9-
(* open Egraph_matcher *)
10-
11-
(* let elim_join_nest g _ = *)
12-
(* let%bind root, join = M.any_join g in *)
13-
(* let scope = Fresh.name Global.fresh "s%d" in *)
14-
(* let pred = Pred.scoped (schema r1) scope pred in *)
15-
(* let lhs = *)
16-
(* let scalars = *)
17-
(* Schema.schema r1 |> Schema.scoped scope |> List.map ~f:C.scalar_name *)
18-
(* in *)
19-
(* A.tuple scalars Cross *)
20-
(* and rhs = A.filter pred r2 in *)
21-
(* return (root, C.list join.r1 @@ A.tuple [ lhs; rhs ] Cross) *)
22-
23-
(* let elim_join_nest = of_func elim_join_nest ~name:"elim-join-nest" *)
24-
25-
(* let elim_join_hash r = *)
26-
(* let open Option.Let_syntax in *)
27-
(* let%bind pred, r1, r2 = to_join r in *)
28-
(* match pred with *)
29-
(* | `Binop (Eq, kl, kr) -> *)
30-
(* let join_scope = Fresh.name Global.fresh "s%d" *)
31-
(* and hash_scope = Fresh.name Global.fresh "s%d" *)
32-
(* and r1_schema = schema r1 in *)
33-
(* let key_name = Fresh.name Global.fresh "k%d" in *)
34-
(* let layout = *)
35-
(* let slist = *)
36-
(* let r1_schema = Schema.scoped join_scope r1_schema in *)
37-
(* r1_schema @ schema r2 |> Select_list.of_names *)
38-
(* in *)
39-
(* A.dep_join r1 join_scope @@ A.select slist *)
40-
(* @@ A.hash_idx *)
41-
(* (A.dedup @@ A.select [ (kr, key_name) ] r2) *)
42-
(* hash_scope *)
43-
(* (A.filter *)
44-
(* (`Binop *)
45-
(* (Eq, `Name (Name.create ~scope:hash_scope key_name), kr)) *)
46-
(* r2) *)
47-
(* [ Pred.scoped r1_schema join_scope kl ] *)
48-
(* in *)
49-
(* Some layout *)
50-
(* | _ -> None *)
51-
52-
(* let elim_join_hash = of_func elim_join_hash ~name:"elim-join-hash" *)
53-
54-
(* let elim_join_filter r = *)
55-
(* let open Option.Let_syntax in *)
56-
(* let%map pred, r1, r2 = to_join r in *)
57-
(* A.filter pred (A.join (`Bool true) r1 r2) *)
58-
59-
(* let elim_join_filter = of_func elim_join_filter ~name:"elim-join-filter" *)
1+
open Core
2+
module Subst = Castor.Subst
3+
module Schema = Castor.Schema
4+
module Name = Castor.Name
5+
module Free = Castor.Free
6+
module Abslayout = Castor.Abslayout
7+
module Pred = Castor.Pred
8+
module Select_list = Castor.Select_list
9+
module Fresh = Castor.Fresh
10+
module Global = Castor.Global
11+
module Egraph = Castor.Egraph
12+
module P = Pred.Infix
13+
module A = Abslayout
14+
open Egraph_matcher
15+
16+
let elim_join_nest g _ =
17+
let%map root, join = M.any_join g in
18+
let lhs_schema = G.schema g join.r1 in
19+
let pred =
20+
Subst.subst_pred
21+
(List.map lhs_schema ~f:(fun n -> (n, `Name (Name.zero n)))
22+
|> Map.of_alist_exn (module Name))
23+
join.pred
24+
in
25+
let lhs = C.tuple g (List.map lhs_schema ~f:(C.scalar_name g)) Cross
26+
and rhs = C.filter g pred (of_annot g @@ Subst.incr @@ to_annot g join.r2) in
27+
(root, C.depjoin g { d_lhs = join.r1; d_rhs = C.tuple g [ lhs; rhs ] Cross })
28+
29+
let elim_join_hash g _ =
30+
let%bind root, join = M.any_join g in
31+
match join.pred with
32+
| `Binop (Eq, kl, kr) ->
33+
let r1_schema = G.schema g join.r1 in
34+
let kl =
35+
Subst.incr_pred kl
36+
|> Subst.subst_pred
37+
(Map.of_alist_exn (module Name)
38+
@@ List.map r1_schema ~f:(fun n -> (n, `Name (Name.zero n))))
39+
in
40+
let layout =
41+
let slist =
42+
Select_list.of_names
43+
(List.map ~f:Name.zero r1_schema @ G.schema g join.r2)
44+
in
45+
C.depjoin g
46+
{
47+
d_lhs = join.r1;
48+
d_rhs =
49+
C.select g slist
50+
@@ C.hash_idx g
51+
{
52+
hi_keys =
53+
C.dedup g
54+
@@ C.select g [ (kr, "key") ]
55+
@@ of_annot g @@ Subst.incr @@ to_annot g join.r2;
56+
hi_values =
57+
C.filter g
58+
(`Binop
59+
(Eq, `Name (Name.zero @@ Name.create "key"), kr))
60+
@@ of_annot g @@ Subst.incr @@ Subst.incr
61+
@@ to_annot g join.r2;
62+
hi_lookup = [ kl ];
63+
hi_key_layout = None;
64+
};
65+
}
66+
in
67+
return (root, layout)
68+
| _ -> empty
69+
70+
let elim_join_filter g _ =
71+
let%map root, join = M.any_join g in
72+
(root, C.filter g join.pred (C.join g (`Bool true) join.r1 join.r2))
6073

6174
(* let hoist_join_param_filter r = *)
6275
(* let open Option.Let_syntax in *)
@@ -163,3 +176,8 @@
163176
(* * return *)
164177
(* * @@ A.filter (Pred.conjoin hoist) *)
165178
(* * @@ A.join (Pred.conjoin keep) r1 r2 *\) *)
179+
180+
let () =
181+
Ops.register elim_join_nest "elim-join-nest";
182+
Ops.register elim_join_hash "elim-join-hash";
183+
Ops.register elim_join_hash "elim-join-filter"

eopt/subsumption_tactics.ml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
let

flake.nix

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
inputs = {
3+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4+
flake-utils.url = "github:numtide/flake-utils";
5+
combinat.url = "github:jfeser/combinat";
6+
combinat.inputs.nixpkgs.follows = "nixpkgs";
7+
};
8+
outputs = { self, flake-utils, nixpkgs, combinat }@inputs:
9+
flake-utils.lib.eachSystem [ "aarch64-darwin" "x86_64-linux" ] (system:
10+
let
11+
pkgs = import nixpkgs {
12+
inherit system;
13+
overlays = [ self.overlay.${system} combinat.overlay.${system} ];
14+
};
15+
in {
16+
overlay = self: super: {
17+
ocamlPackages = super.ocaml-ng.ocamlPackages_4_14.overrideScope'
18+
(self: super: {
19+
ocaml = super.ocaml.override { flambdaSupport = true; };
20+
castor = super.buildDunePackage rec {
21+
pname = "castor";
22+
version = "0.1";
23+
duneVersion = "3";
24+
minimalOCamlVersion = "4.13";
25+
propagatedBuildInputs = [
26+
self.core
27+
self.core_bench
28+
self.core_unix
29+
self.ppx_yojson_conv
30+
self.menhir
31+
self.fmt
32+
self.yojson
33+
self.gen
34+
self.iter
35+
self.bheap
36+
self.logs
37+
self.combinat
38+
self.bitarray
39+
self.vpt
40+
self.base
41+
self.fmt
42+
self.sek
43+
];
44+
src = ./.;
45+
};
46+
});
47+
};
48+
49+
defaultPackage = pkgs.ocamlPackages.symetric;
50+
devShell = pkgs.mkShell {
51+
nativeBuildInputs = [ pkgs.ocamlformat ];
52+
inputsFrom = [ pkgs.ocamlPackages.symetric ];
53+
};
54+
});
55+
}

lib/pred.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ open Ast
33
module Binop = Ast.Binop
44
module Unop = Ast.Unop
55

6-
type t = Ast.t Ast.pred [@@deriving compare, hash, sexp]
6+
type t = Ast.t Ast.pred [@@deriving compare, equal, hash, sexp]
77

88
include Comparator.S with type t := t
99
module O : Comparable.Infix with type t := t

lib/sql.ml

+8-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module P = Pred.Infix
88
include (val Log.make "castor.sql")
99

1010
type select_entry = { pred : Pred.t; alias : string; cast : Prim_type.t option }
11-
[@@deriving compare, sexp_of]
11+
[@@deriving compare, equal, sexp_of]
1212

1313
type 'r spj = {
1414
select : select_entry list;
@@ -19,7 +19,7 @@ type 'r spj = {
1919
group : Pred.t list;
2020
limit : int option;
2121
}
22-
[@@deriving compare, sexp_of]
22+
[@@deriving compare, equal, sexp_of]
2323

2424
type 'q compound_relation =
2525
[ `Subquery of 'q | `Table of Relation.t | `Series of Pred.t * Pred.t ]
@@ -297,8 +297,7 @@ let relation Relation.({ r_name = tbl; _ } as rel) =
297297
let relations = [ (`Table rel, tbl, `Left) ] in
298298
`Query (create_spj ~relations select_list)
299299

300-
let of_ralgebra_open f r =
301-
match r.node with
300+
let of_query_open f = function
302301
| Range (p, p') ->
303302
let alias = Fresh.name Global.fresh "t%d" in
304303
`Query
@@ -323,16 +322,17 @@ let of_ralgebra_open f r =
323322
| ATuple (rs, Concat) -> `Union_all (List.map ~f:(fun r -> to_spj (f r)) rs)
324323
| ATuple ([], _) | AEmpty -> `Query (create_spj ~limit:0 [])
325324
| AScalar p -> `Query (create_spj [ create_entry p.s_pred ~alias:p.s_name ])
326-
| ATuple (_, Zip) ->
327-
Error.(create "Unsupported." r [%sexp_of: _ annot] |> raise)
325+
| ATuple (_, Zip) -> failwith "zip tuples are unsupported"
328326
| AList l -> f @@ A.dep_join' (Layout_to_depjoin.list l)
329327
| AHashIdx h -> f @@ A.dep_join' (Layout_to_depjoin.hash_idx h)
330328
| AOrderedIdx o -> f @@ A.dep_join' (Layout_to_depjoin.ordered_idx o)
331329
| _ -> failwith "unsupported"
332330

331+
let of_annot_open f r = of_query_open f r.node
332+
333333
let of_ralgebra x =
334-
let rec f x = of_ralgebra_open f x in
335-
f (strip_meta x)
334+
let rec f x = of_annot_open f x in
335+
f x
336336

337337
let name_to_sql (n : Name.t) =
338338
match n.name with

lib/sql.mli

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type 'r spj = {
1212
group : Pred.t list;
1313
limit : int option;
1414
}
15-
[@@deriving compare, sexp_of]
15+
[@@deriving compare, equal, sexp_of]
1616

1717
type 'q compound_relation =
1818
[ `Subquery of 'q | `Table of Relation.t | `Series of Pred.t * Pred.t ]
@@ -42,7 +42,7 @@ val create_entry_s :
4242

4343
val create_entries_s : string list -> select_entry list
4444
val src : Logs.Src.t
45-
val of_ralgebra : < .. > annot -> t
45+
val of_ralgebra_open : (< > annot -> t) -> < > annot -> t
4646
val has_aggregates : t -> bool
4747
val to_schema : t -> string list
4848
val sample : int -> string -> string

lib/subst.ml

+8-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ let decr_pred p =
1313

1414
let decr_pred_exn p = Pred.map_names ~f:(fun n -> `Name (Name.decr_exn n)) p
1515

16+
let rec shift_pred ~cutoff d = function
17+
| `Name n -> `Name (Name.shift ~cutoff d n)
18+
| p -> Visitors.Map.pred Fun.id (shift_pred ~cutoff d) p
19+
1620
let rec shift ~cutoff d r = { r with node = shift_query ~cutoff d r.node }
1721

1822
and shift_query ~cutoff:c d =
@@ -48,10 +52,6 @@ and shift_lookup ~cutoff d =
4852

4953
and shift_bound ~cutoff d (p, b) = (shift_pred ~cutoff d p, b)
5054

51-
and shift_pred ~cutoff d = function
52-
| `Name n -> `Name (Name.shift ~cutoff d n)
53-
| p -> Visitors.Map.pred Fun.id (shift_pred ~cutoff d) p
54-
5555
let incr x = shift ~cutoff:0 1 x
5656
let incr_pred x = shift_pred ~cutoff:0 1 x
5757

@@ -60,6 +60,10 @@ let incr_ctx ctx =
6060
|> List.map ~f:(fun (n, p) -> (Name.incr n, incr_pred p))
6161
|> Map.of_alist_exn (module Name)
6262

63+
let rec subst_pred ctx = function
64+
| `Name n as p -> Map.find ctx n |> Option.value ~default:p
65+
| p -> Visitors.Map.pred Fun.id (subst_pred ctx) p
66+
6367
let rec subst ctx r = { r with node = subst_query ctx r.node }
6468

6569
and subst_query ctx = function
@@ -95,7 +99,3 @@ and subst_lookup ctx =
9599
(Option.map l ~f:(subst_bound ctx), Option.map h ~f:(subst_bound ctx)))
96100

97101
and subst_bound ctx (p, b) = (subst_pred ctx p, b)
98-
99-
and subst_pred ctx = function
100-
| `Name n as p -> Map.find ctx n |> Option.value ~default:p
101-
| p -> Visitors.Map.pred Fun.id (subst_pred ctx) p

lib/subst.mli

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ open Core
22
open Ast
33

44
val incr : 'm annot -> 'm annot
5-
val incr_pred : 'm annot pred -> 'm annot pred
5+
val incr_pred : 'r pred -> 'r pred
66
val incr_ctx : 'm annot pred Map.M(Name).t -> 'm annot pred Map.M(Name).t
77
val decr_pred : 'a pred -> 'a pred option
88
val decr_pred_exn : 'a pred -> 'a pred
9+
val subst_pred : 'r pred Map.M(Name).t -> 'r pred -> 'r pred
910
val subst : 'm annot pred Map.M(Name).t -> 'm annot -> 'm annot

lib/subsumption.ml

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ open Collections
33
open Ast
44
open Sql
55

6+
type t = (Relation.t * string) spj [@@deriving sexp_of, equal]
7+
68
module Foreign_key_join_graph = struct
79
module Edge = struct
810
type t = { l_attr : string; r_attr : string } [@@deriving compare]

test/eopt/dune.inc

+11
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@
2121
(run ../bin/eopt.exe)))))
2222

2323

24+
(rule
25+
(alias runtest)
26+
(action (diff elim-join.sexp.expected elim-join.sexp.output)))
27+
28+
(rule
29+
(alias runtest)
30+
(action (with-stdout-to elim-join.sexp.output
31+
(with-stdin-from elim-join.sexp
32+
(run ../bin/eopt.exe)))))
33+
34+
2435
(rule
2536
(alias runtest)
2637
(action (diff hoist-filter-select.sexp.expected hoist-filter-select.sexp.output)))

test/eopt/elim-join.sexp

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
((queries
2+
"join(f = g, ascalar(1 as f), ascalar(0 as g))")
3+
(transforms elim-join-nest elim-join-hash elim-join-filter))

test/eopt/elim-join.sexp.expected

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
$2:
2+
join((f = g), ascalar(1 as f), ascalar(0 as g))
3+
depjoin(ascalar(1 as f), atuple([atuple([ascalar(f)], cross),
4+
filter((0.f = g), ascalar(0 as g))], cross))
5+
depjoin(ascalar(1 as f), select([0.f, g], ahashidx(dedup(select([g as key], ascalar(0 as g))), filter((0.key
6+
= g), ascalar(0 as g)), 0.f)))
7+

test/eopt/multi-query.sexp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
((queries
22
"select([l_shipdate], filter(l_orderkey = param0, lineitem))"
33
"join(l_orderkey = o_orderkey, lineitem, orders)")
4-
(transforms elim-eq-filter)
4+
(transforms elim-eq-filter elim-join-hash)
55
(db postgresql:///tpch_1k))

0 commit comments

Comments
 (0)