Class: Bmg::Sql::Support::FromClauseOrderer

Inherits:
Object
  • Object
show all
Defined in:
lib/bmg/sql/support/from_clause_orderer.rb

Instance Method Summary collapse

Instance Method Details

#call(sexpr) ⇒ Object

Given a ‘from_clause` AST as input, e.g.

[ :from_clause,
  [ :cross_join
    [ :inner_join,
      [ :inner_join,
        [ :table_as, "suppliers", "s"  ],
        [ :table_as, "supplies",  "sp" ],
        [ :eq, [ :qualified, "s", "sid" ], [ :qualified, "sp", "sid" ] ]
      ],
      [ :table_as, "parts", "p" ],
      [ :eq, [ :qualified, "p", "pid" ], [ :qualified "sp", "pid" ] ]
    ],
    [ :table_as, "cities", "c" ],
  ]
]

Generates a relationally equivalent list of (type,table,predicate) triplets, where:

  • type is :base, :cross_join, :inner_join, or :left_join

  • table is table_as, native_table_as or subquery_as

  • predicate is a join predicate ‘ti.attri = tj.attrj AND …`

So that

1) the types are observed in strict increasing order (one :base, zero

or more :cross_join, zero or more :inner_join, zero or more :left_join)

2) the list is such that it can be safely written as an expression

 of the following SQL syntax:

    t1                            # [ :base, t1, nil ]
    cross_join t2                 # [ :cross_join, t2, nil ]
    cross_join t3                 # [ :cross_join, t3, nil ]
    inner_join t4 ON p4           # [ :inner_join, t4, p4 ]
    inner_join t5 ON p5           # [ :inner_join, t5, p5 ]
    left_join t6 ON p6            # [ :left_join, t6, p6 ]

that is, the linearization is correct only if each predicate `pi`
only makes reference to tables introduced before it (no forward
reference).

For the example above, a solution might be:

[
  [ :base,       [ :table_as, "suppliers", "s"  ], nil ],
  [ :cross_join, [ :table_as, "cities", "c" ],     nil ],
  [ :inner_join, [ :table_as, "supplies",  "sp" ],
      [ :eq, [ :qualified, "s", "sid" ], [ :qualified, "sp", "sid" ] ] ],
  [ :inner_join, [ :table_as, "parts", "p" ],
      [ :eq, [ :qualified, "p", "pid" ], [ :qualified "sp", "pid" ] ] ]
]

A NotImplementedError may be raised if no linearization can be found.



62
63
64
65
66
67
68
69
70
# File 'lib/bmg/sql/support/from_clause_orderer.rb', line 62

def call(sexpr)
  # The algorithm works in two phases: we first collect all table
  # references and JOIN clauses by simple inspection of the AST.
  tables, joins = collect(sexpr)

  # Then we order the tables and join clauses so as to find the
  # linearization.
  order_all(tables, joins)
end