Edit on GitHub

sqlglot.optimizer.lower_identities

 1from sqlglot import exp
 2
 3
 4def lower_identities(expression):
 5    """
 6    Convert all unquoted identifiers to lower case.
 7
 8    Assuming the schema is all lower case, this essentially makes identifiers case-insensitive.
 9
10    Example:
11        >>> import sqlglot
12        >>> expression = sqlglot.parse_one('SELECT Bar.A AS A FROM "Foo".Bar')
13        >>> lower_identities(expression).sql()
14        'SELECT bar.a AS A FROM "Foo".bar'
15
16    Args:
17        expression (sqlglot.Expression): expression to quote
18    Returns:
19        sqlglot.Expression: quoted expression
20    """
21    # We need to leave the output aliases unchanged, so the selects need special handling
22    _lower_selects(expression)
23
24    # These clauses can reference output aliases and also need special handling
25    _lower_order(expression)
26    _lower_having(expression)
27
28    # We've already handled these args, so don't traverse into them
29    traversed = {"expressions", "order", "having"}
30
31    if isinstance(expression, exp.Subquery):
32        # Root subquery, e.g. (SELECT A AS A FROM X) LIMIT 1
33        lower_identities(expression.this)
34        traversed |= {"this"}
35
36    if isinstance(expression, exp.Union):
37        # Union, e.g. SELECT A AS A FROM X UNION SELECT A AS A FROM X
38        lower_identities(expression.left)
39        lower_identities(expression.right)
40        traversed |= {"this", "expression"}
41
42    for k, v in expression.iter_expressions():
43        if k in traversed:
44            continue
45        v.transform(_lower, copy=False)
46
47    return expression
48
49
50def _lower_selects(expression):
51    for e in expression.expressions:
52        # Leave output aliases as-is
53        e.unalias().transform(_lower, copy=False)
54
55
56def _lower_order(expression):
57    order = expression.args.get("order")
58
59    if not order:
60        return
61
62    output_aliases = {e.alias for e in expression.expressions if isinstance(e, exp.Alias)}
63
64    for ordered in order.expressions:
65        # Don't lower references to output aliases
66        if not (
67            isinstance(ordered.this, exp.Column)
68            and not ordered.this.table
69            and ordered.this.name in output_aliases
70        ):
71            ordered.transform(_lower, copy=False)
72
73
74def _lower_having(expression):
75    having = expression.args.get("having")
76
77    if not having:
78        return
79
80    # Don't lower references to output aliases
81    for agg in having.find_all(exp.AggFunc):
82        agg.transform(_lower, copy=False)
83
84
85def _lower(node):
86    if isinstance(node, exp.Identifier) and not node.quoted:
87        node.set("this", node.this.lower())
88    return node
def lower_identities(expression):
 5def lower_identities(expression):
 6    """
 7    Convert all unquoted identifiers to lower case.
 8
 9    Assuming the schema is all lower case, this essentially makes identifiers case-insensitive.
10
11    Example:
12        >>> import sqlglot
13        >>> expression = sqlglot.parse_one('SELECT Bar.A AS A FROM "Foo".Bar')
14        >>> lower_identities(expression).sql()
15        'SELECT bar.a AS A FROM "Foo".bar'
16
17    Args:
18        expression (sqlglot.Expression): expression to quote
19    Returns:
20        sqlglot.Expression: quoted expression
21    """
22    # We need to leave the output aliases unchanged, so the selects need special handling
23    _lower_selects(expression)
24
25    # These clauses can reference output aliases and also need special handling
26    _lower_order(expression)
27    _lower_having(expression)
28
29    # We've already handled these args, so don't traverse into them
30    traversed = {"expressions", "order", "having"}
31
32    if isinstance(expression, exp.Subquery):
33        # Root subquery, e.g. (SELECT A AS A FROM X) LIMIT 1
34        lower_identities(expression.this)
35        traversed |= {"this"}
36
37    if isinstance(expression, exp.Union):
38        # Union, e.g. SELECT A AS A FROM X UNION SELECT A AS A FROM X
39        lower_identities(expression.left)
40        lower_identities(expression.right)
41        traversed |= {"this", "expression"}
42
43    for k, v in expression.iter_expressions():
44        if k in traversed:
45            continue
46        v.transform(_lower, copy=False)
47
48    return expression

Convert all unquoted identifiers to lower case.

Assuming the schema is all lower case, this essentially makes identifiers case-insensitive.

Example:
>>> import sqlglot
>>> expression = sqlglot.parse_one('SELECT Bar.A AS A FROM "Foo".Bar')
>>> lower_identities(expression).sql()
'SELECT bar.a AS A FROM "Foo".bar'
Arguments:
  • expression (sqlglot.Expression): expression to quote
Returns:

sqlglot.Expression: quoted expression