Skip to content

Commit e141960

Browse files
authored
Feat!: improve transpilation of CHAR[ACTER]_LENGTH (#4555)
* CHAR_LENGTH for postgres * len(x) fixed * postgress fixed * len removed from postgres * psql add length(x, ecoding) and test
1 parent d32d26a commit e141960

File tree

6 files changed

+14
-4
lines changed

6 files changed

+14
-4
lines changed

sqlglot/dialects/mysql.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,6 @@ class Parser(parser.Parser):
295295

296296
FUNCTIONS = {
297297
**parser.Parser.FUNCTIONS,
298-
"CHAR_LENGTH": exp.Length.from_arg_list,
299-
"CHARACTER_LENGTH": exp.Length.from_arg_list,
300298
"CONVERT_TZ": lambda args: exp.ConvertTimezone(
301299
source_tz=seq_get(args, 1), target_tz=seq_get(args, 2), timestamp=seq_get(args, 0)
302300
),
@@ -311,6 +309,7 @@ class Parser(parser.Parser):
311309
"FORMAT": exp.NumberToStr.from_arg_list,
312310
"FROM_UNIXTIME": build_formatted_time(exp.UnixToTime, "mysql"),
313311
"ISNULL": isnull_to_is_null,
312+
"LENGTH": lambda args: exp.Length(this=seq_get(args, 0), binary=True),
314313
"LOCATE": locate_to_strposition,
315314
"MAKETIME": exp.TimeFromParts.from_arg_list,
316315
"MONTH": lambda args: exp.Month(this=exp.TsOrDsToDate(this=seq_get(args, 0))),
@@ -731,7 +730,6 @@ class Generator(generator.Generator):
731730
e: f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""",
732731
exp.ILike: no_ilike_sql,
733732
exp.JSONExtractScalar: arrow_json_extract_sql,
734-
exp.Length: rename_func("CHAR_LENGTH"),
735733
exp.LogicalOr: rename_func("MAX"),
736734
exp.LogicalAnd: rename_func("MIN"),
737735
exp.Max: max_or_greatest,
@@ -1265,3 +1263,7 @@ def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
12651263

12661264
def isascii_sql(self, expression: exp.IsAscii) -> str:
12671265
return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')"
1266+
1267+
def length_sql(self, expression: exp.Length) -> str:
1268+
length_func = "LENGTH" if expression.args.get("binary") else "CHAR_LENGTH"
1269+
return self.func(length_func, expression.this)

sqlglot/dialects/postgres.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ class Parser(parser.Parser):
377377
"GENERATE_SERIES": _build_generate_series,
378378
"JSON_EXTRACT_PATH": build_json_extract_path(exp.JSONExtract),
379379
"JSON_EXTRACT_PATH_TEXT": build_json_extract_path(exp.JSONExtractScalar),
380+
"LENGTH": lambda args: exp.Length(this=seq_get(args, 0), encoding=seq_get(args, 1)),
380381
"MAKE_TIME": exp.TimeFromParts.from_arg_list,
381382
"MAKE_TIMESTAMP": exp.TimestampFromParts.from_arg_list,
382383
"NOW": exp.CurrentTimestamp.from_arg_list,

sqlglot/expressions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6153,7 +6153,7 @@ class Right(Func):
61536153

61546154

61556155
class Length(Func):
6156-
arg_types = {"this": True, "binary": False}
6156+
arg_types = {"this": True, "binary": False, "encoding": False}
61576157
_sql_names = ["LENGTH", "LEN"]
61586158

61596159

sqlglot/parser.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ class Parser(metaclass=_Parser):
188188
this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
189189
),
190190
"CHAR": lambda args: exp.Chr(expressions=args),
191+
"CHAR_LENGTH": exp.Length.from_arg_list,
192+
"CHARACTER_LENGTH": exp.Length.from_arg_list,
191193
"CHR": lambda args: exp.Chr(expressions=args),
192194
"COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
193195
"CONCAT": lambda args, dialect: exp.Concat(

tests/dialects/test_mysql.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ def test_mysql(self):
725725
write={
726726
"duckdb": "SELECT LENGTH('foo')",
727727
"mysql": "SELECT CHAR_LENGTH('foo')",
728+
"postgres": "SELECT LENGTH('foo')",
728729
},
729730
)
730731

tests/dialects/test_postgres.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ def test_postgres(self):
4949
self.validate_identity("CAST(x AS DATERANGE)")
5050
self.validate_identity("CAST(x AS DATEMULTIRANGE)")
5151
self.validate_identity("x$")
52+
self.validate_identity("LENGTH(x)")
53+
self.validate_identity("LENGTH(x, utf8)")
54+
self.validate_identity("CHAR_LENGTH(x)", "LENGTH(x)")
55+
self.validate_identity("CHARACTER_LENGTH(x)", "LENGTH(x)")
5256
self.validate_identity("SELECT ARRAY[1, 2, 3]")
5357
self.validate_identity("SELECT ARRAY(SELECT 1)")
5458
self.validate_identity("STRING_AGG(x, y)")

0 commit comments

Comments
 (0)