class Bmg::Sql::Support::FromClauseOrderer
Public Instance Methods
call(sexpr)
click to toggle source
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.
# 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