the script writer s dream how to write great sql in your
play

The script-writers dream: How to write great SQL in your own - PowerPoint PPT Presentation

The script-writers dream: How to write great SQL in your own language and be sure it will succeed. Ezra Cooper University of Edinburgh August 24, 2009 The Problem The Problem The Problem Problems with SQL: Embedding is usually a


  1. The script-writer’s dream: How to write great SQL in your own language and be sure it will succeed. Ezra Cooper University of Edinburgh August 24, 2009

  2. The Problem

  3. The Problem

  4. The Problem Problems with SQL: ◮ Embedding is usually a pain ◮ Lacks nested data structures ◮ Lacks abstraction

  5. The Problem Problems with SQL: ◮ Embedding is usually a pain ◮ Lacks nested data structures ◮ Lacks abstraction The Solution Language-integrated query

  6. Example: Little League database name Marchmont United teams: Bruntsfield Hustlers Newington Numpties Leith Sluggers name team age Sam Marchmont United 17 Ezra Bruntsfield Hustlers 15 Angus Newington Numpties 18 players: Jeremy Newington Numpties 15 Paidi Leith Sluggers 15 Bob Newington Numpties 14 Lucy Leith Sluggers 17 Hugh Bruntsfield Hustlers 13

  7. Meet the comprehension for ( x ← src ) body

  8. Meet the comprehension for ( x ← src ) body Bind x to successive values from src evaluating body for each one; the result is the union of all the collections so produced.

  9. Meet the comprehension for ( x ← src ) body Bind x to successive values from src evaluating body for each one; the result is the union of all the collections so produced. Some syntactic sugar: for ( x ← src ) where ( cond ) body = for ( x ← src ) ( if ( cond ) then body else [] )

  10. Example: A simple query var players = table “ players ” : [( age : int , name : string )]; fun overAgePlayers () { query { for ( p ← players ) where ( p . age > 16) [ ( name = p . name ) ] } }

  11. Example: A simple query var players = table “ players ” : [( age : int , name : string )]; fun overAgePlayers () { query { for ( p ← players ) where ( p . age > 16) [ ( name = p . name ) ] } } SQL: select p.name as name from players as p where p.age > 16

  12. Example: Detecting non-queryizable operations fun overAgePlayersReversed () { query { for ( p ← players ) where ( p . age > 16) [ ( name = reverse ( p . name )) ] # ERROR! } }

  13. Example: Abstracting the query fun selectedPlayers ( pred ) { query { for ( p ← players ) where ( pred ( p )) [ ( name = p . name ) ] } }

  14. Example: Abstracting the query fun selectedPlayers ( pred ) { query { for ( p ← players ) where ( pred ( p )) [ ( name = p . name ) ] } } SQL ?? select p.name as name from players as p [ · · · ] where

  15. Example: Nested query fun unusablePlayers () { query { var teamRosters : [ ( roster : [ Player ] ) ] = for ( t ← teams ) [ ( roster = for ( p ← players ) where ( p . team == t . name ) [ p ] ) ] ; for ( tr ← teamRosters ) where ( length ( tr . roster ) < 9) tr . roster } }

  16. Example: Nested query, unnested as SQL SQL: select p .* from players as p , teams as t where p .team = t .name and ((select count(*) from players as p2 where p2 .team = t .name) < 9)

  17. Example: Nested query, refactored fun teamRosters () { for ( t ← teams ) [ ( name = t . name roster = for ( p ← players ) where ( p . team == t . team )) [ p ]] ; } fun unusablePlayers () { query { for ( tr ← teamRosters () ) where ( length ( tr . roster ) < 9) tr . roster } }

  18. Example: Nested query, abstracted fun unusablePlayers ( pred ) { query { for ( t ← teamRosters () ) where ( pred ( t . roster )) t . roster } }

  19. Example: Nested query, abstracted fun unusablePlayers ( pred ) { query { for ( t ← teamRosters () ) where ( pred ( t . roster )) t . roster } } Very hard in SQL

  20. Example: Nested query, abstracted, attempted in SQL select p.* from players as p, teams as t where p.team = t.name and ((select count(*) from players as p2 where p2.team = t.name) < 9)

  21. The goal Write queries in an ordinary programming language.

  22. The goal Write queries in an ordinary programming language. ◮ Allow nested data structures.

  23. The goal Write queries in an ordinary programming language. ◮ Allow nested data structures. ◮ Allow abstraction.

  24. The goal Write queries in an ordinary programming language. ◮ Allow nested data structures. ◮ Allow abstraction. ◮ Statically detect unqueryizable expressions.

  25. The goal Write queries in an ordinary programming language. ◮ Allow nested data structures. ◮ Allow abstraction. ◮ Statically detect unqueryizable expressions. “Language-integrated query”

  26. Previous work, language-integrated query ◮ Libkin and Wong (early 90s): Theory; proof for first-order unnesting, pure setting, total. ◮ Kleisli, LINQ, Links (originally): Implemented, impure setting, partial. ◮ Ferry (Grust, et al., 2009): Implemented, pure setting, total, handles nested final results. ◮ Fegaras (1998): Theory, higher-order, but no proof of termination. ◮ Van den Bussche (2001): Theory, nested final results.

  27. Example: Nested query with untranslatable fragment fun teamRosters () { query { for ( t ← teams ) [ ( name = reverse ( t . name ) # ERROR! roster = for ( p ← players ) where ( p . team == t . team )) [ p ]] ; } }

  28. Example: Nested query with untranslatable fragment fun teamRosters () { query { for ( t ← teams ) [ ( name = reverse ( t . name ) # ERROR! roster = for ( p ← players ) where ( p . team == t . team )) [ p ]] ; } } Original version of Links, like Kleisli, translates this to an iteration over a query—one players query for each row of teams .

  29. What I want to show you

  30. What I want to show you How to translate any “pure” expression of relational type to an equivalent single SQL query.

  31. What I want to show you How to translate any “pure” expression of relational type to an equivalent single SQL query. and How to statically detect whether a designated expression is queryizable.

  32. The contribution Add to language-integrated query ◮ Handling higher-order functions. ◮ Separating query-translatable from non-translatable sublanguages of a general-purpose language. ◮ Providing a complete translation from the translatable sublanguage.

  33. The Solution

  34. Plan Compile time Run time Type-and-effect check Normalize Translate

  35. The source language o | ( − − → e (types) T ::= l : T ) | [ T ] | S → T (base types) ::= bool | int | string | · · · o (terms) B , L , M , N ::= for ( x ← L ) M | if B then M else N | table s : T | [ M ] | [] | M ⊎ N ( − − − → | l = M ) | M . l | LM | λ x . N | x | c | length ( M ) | empty ( M ) prim ( − → | M ) | query { M } (atomic effects) ::= noQ E (effect sets) e a set of effects E

  36. Type-and-effect checking

  37. Typing judgment Γ ⊢ M : T ! e Γ variable typing environment M expression T type of M e effects (a set) “In environment Γ, evaluating expression M has effects contained in e and results in type T .”

  38. Typing rules T has the form [ ( − − → Γ ⊢ M : T ! ∅ l : o ) ] ( T-Query ) Γ ⊢ query { M } : T ! ∅

  39. Typing rules e prim : S 1 × · · · × S n → T Γ ⊢ M i : S i ! e i for each 1 ≤ i ≤ n ( T-Prim ) Γ ⊢ prim ( − → M ) : T ! e ∪ � i e i

  40. Typing rules e prim : S 1 × · · · × S n → T Γ ⊢ M i : S i ! e i for each 1 ≤ i ≤ n ( T-Prim ) Γ ⊢ prim ( − → M ) : T ! e ∪ � i e i Side condition: Every primitive must have an SQL equivalent or an effect tag.

  41. Typing rules T has the form [ ( − − → l : o ) ] ( T-Table ) Γ ⊢ ( table s : T ) : T ! ∅

  42. Typing rules Γ , x : S ⊢ N : [ T ] ! e ′ Γ ⊢ M : [ S ] ! e ( T-For ) Γ ⊢ for ( x ← M ) N : [ T ] ! e ∪ e ′

  43. Typing rules Γ ⊢ c : T c ! ∅ ( T-Const ) Γ , x : T ⊢ x : T ! ∅ ( T-Var ) Γ , x : S ⊢ N : T ! e ′ ( T-Abs ) Γ ⊢ λ x . N : S e ′ → T ! ∅ e → T ! e ′ Γ ⊢ M : S ! e ′′ Γ ⊢ L : S ( T-App ) Γ ⊢ LM : T ! e ∪ e ′ ∪ e ′′

  44. Typing rules Γ ⊢ M : [ T ] ( T-Empty ) Γ ⊢ empty ( M ) : bool Γ ⊢ M : [ T ] ( T-Length ) Γ ⊢ length ( M ) : int

  45. Typing rules Γ ⊢ [] : [ T ] ! ∅ ( T-Null ) Γ ⊢ M : T ! e ( T-Singleton ) Γ ⊢ [ M ] : [ T ] ! e Γ ⊢ N : [ T ] ! e ′ Γ ⊢ M : [ T ] ! e ( T-Union ) Γ ⊢ M ⊎ N : [ T ] ! e ∪ e ′

  46. Typing rules Γ ⊢ M i : T i ! e i for each M i , T i in − − − → M , T ( T-Record ) Γ ⊢ ( − l = M ) : ( − − − → − → l : T ) ! � i e i Γ ⊢ M : ( − − → ( l : T ) ∈ ( − − → l : T ) ! e l : T ) ( T-Project ) Γ ⊢ M . l : T ! e Γ ⊢ M : T ! e ′ Γ ⊢ N : T ! e ′′ Γ ⊢ L : bool ! e ( T-If ) Γ ⊢ if L then M 1 else M 2 : T ! e ∪ e ′ ∪ e ′′ e e ⊂ e ′ Γ ⊢ M : S → T ( T-Subsump ) Γ ⊢ M : S e ′ → T

  47. What the typing gives us Any well-typed expression query { M } : has relation type and never executes any primitive that lacks an SQL equivalent.

  48. What the typing gives us Any well-typed expression query { M } : has relation type and never executes any primitive that lacks an SQL equivalent. So, at runtime M can be translated to an SQL query.

  49. Run Time

  50. Translation

  51. Normal forms (normal forms) V , U ::= V ⊎ U | [] | F (comprehension NFs) ::= for ( x ← table s : T ) F | Z F (comprehension bodies) Z ::= if B then Z else [] | [ ( − − − → l = B ) ] | table s : T if B then B ′ else B ′′ | (basic expressions) B ::= empty ( V ) | length ( V ) | prim ( − → B ) | x . l | c

Recommend


More recommend