// Port of sqlglot/optimizer/optimizer.py.
///|
/// The keyword arguments `optimize` passes to its rules (Python's `possible_kwargs`).
pub struct OptimizeOptions {
schema : MappingSchema
db : String?
catalog : String?
dialect : @core.Dialect
sql : String?
isolate_tables : Bool
quote_identifiers : Bool
infer_schema : Bool?
identify : Bool
leave_tables_isolated : Bool
validate_qualify_columns : Bool
canonicalize_table_aliases : Bool
expand_alias_refs : Bool
expand_stars : Bool
allow_partial_qualification : Bool
on_qualify : ((@core.Expr) -> Unit)?
constant_propagation : Bool
coalesce_simplification : Bool
}
///|
/// An optimizer rule.
pub(all) enum Rule {
Qualify
QualifyTables
QualifyColumns
IsolateTableSelects
PushdownProjections
Normalize
UnnestSubqueries
PushdownPredicates
OptimizeJoins
EliminateSubqueries
MergeSubqueries
EliminateJoins
EliminateCtes
QuoteIdentifiers
AnnotateTypes
Canonicalize
Simplify
CanonicalizeInternalNames
Custom((@core.Expr, OptimizeOptions) -> @core.Expr raise @core.SqlglotError)
}
///|
/// The default optimizer rules (Python `RULES`), in order.
pub let rules : Array[Rule] = [
Qualify, PushdownProjections, Normalize, UnnestSubqueries, PushdownPredicates, OptimizeJoins,
EliminateSubqueries, MergeSubqueries, EliminateJoins, EliminateCtes, QuoteIdentifiers,
AnnotateTypes, Canonicalize, Simplify,
]
///|
/// Applies a single rule with the given options.
pub fn Rule::apply(
self : Rule,
expression : @core.Expr,
o : OptimizeOptions,
) -> @core.Expr raise @core.SqlglotError {
match self {
Qualify =>
qualify(
expression,
dialect=o.dialect,
db?=o.db,
catalog?=o.catalog,
schema=o.schema,
expand_alias_refs=o.expand_alias_refs,
expand_stars=o.expand_stars,
infer_schema?=o.infer_schema,
isolate_tables=o.isolate_tables,
allow_partial_qualification=o.allow_partial_qualification,
validate_qualify_columns=o.validate_qualify_columns,
quote_identifiers=o.quote_identifiers,
identify=o.identify,
canonicalize_table_aliases=o.canonicalize_table_aliases,
on_qualify?=o.on_qualify,
sql?=o.sql,
)
QualifyTables =>
qualify_tables(
expression,
db?=o.db,
catalog?=o.catalog,
on_qualify?=o.on_qualify,
dialect=o.dialect,
canonicalize_table_aliases=o.canonicalize_table_aliases,
)
QualifyColumns =>
qualify_columns(
expression,
o.schema,
expand_alias_refs=o.expand_alias_refs,
expand_stars=o.expand_stars,
infer_schema?=o.infer_schema,
allow_partial_qualification=o.allow_partial_qualification,
)
IsolateTableSelects =>
isolate_table_selects(expression, schema=o.schema, dialect=o.dialect)
PushdownProjections => pushdown_projections(expression)
Normalize => normalize(expression)
UnnestSubqueries => unnest_subqueries(expression)
PushdownPredicates => pushdown_predicates(expression, dialect=o.dialect)
OptimizeJoins => optimize_joins(expression)
EliminateSubqueries => eliminate_subqueries(expression)
MergeSubqueries =>
merge_subqueries(expression, leave_tables_isolated=o.leave_tables_isolated)
EliminateJoins => eliminate_joins(expression)
EliminateCtes => eliminate_ctes(expression)
QuoteIdentifiers =>
quote_identifiers(expression, dialect=o.dialect, identify=o.identify)
AnnotateTypes =>
annotate_types(expression, schema=o.schema, dialect=o.dialect)
Canonicalize => canonicalize(expression, dialect=o.dialect)
Simplify =>
simplify(
expression,
constant_propagation=o.constant_propagation,
coalesce_simplification=o.coalesce_simplification,
dialect=o.dialect,
)
CanonicalizeInternalNames => canonicalize_internal_names(expression)
Custom(f) => f(expression, o)
}
}
///|
/// Rewrite a sqlglot AST into an optimized form.
///
/// `identify` only applies to the `QuoteIdentifiers` rule (the `Qualify` rule receives
/// `quote_identifiers=false`, as in Python). Unless given, `schema` is built from `mapping`.
pub fn optimize(
expression : @core.Expr,
schema? : MappingSchema,
mapping? : Map[String, SchemaNode],
db? : String,
catalog? : String,
dialect? : @core.Dialect,
rules? : Array[Rule] = rules,
sql? : String,
infer_schema? : Bool,
identify? : Bool = true,
leave_tables_isolated? : Bool = false,
validate_qualify_columns? : Bool = true,
canonicalize_table_aliases? : Bool = false,
expand_alias_refs? : Bool = true,
expand_stars? : Bool = true,
allow_partial_qualification? : Bool = false,
isolate_tables? : Bool = true,
quote_identifiers? : Bool = false,
on_qualify? : (@core.Expr) -> Unit,
constant_propagation? : Bool = false,
coalesce_simplification? : Bool = false,
) -> @core.Expr raise @core.SqlglotError {
let schema = ensure_schema(schema?, mapping?, dialect?)
let options : OptimizeOptions = {
schema,
db,
catalog,
dialect: get_dialect(dialect),
sql,
isolate_tables,
quote_identifiers,
infer_schema,
identify,
leave_tables_isolated,
validate_qualify_columns,
canonicalize_table_aliases,
expand_alias_refs,
expand_stars,
allow_partial_qualification,
on_qualify,
constant_propagation,
coalesce_simplification,
}
let mut optimized = expression.copy()
for rule in rules {
optimized = rule.apply(optimized, options)
}
optimized
}
///|
/// Parses `sql` (in `dialect`) and optimizes it.
pub fn optimize_sql(
sql : String,
schema? : MappingSchema,
mapping? : Map[String, SchemaNode],
dialect? : @core.Dialect,
rules? : Array[Rule] = rules,
infer_schema? : Bool,
identify? : Bool = true,
) -> @core.Expr raise @core.SqlglotError {
let expression = @core.parse_one(sql, dialect?)
optimize(
expression,
schema?,
mapping?,
dialect?,
rules~,
infer_schema?,
identify~,
)
}