summaryrefslogtreecommitdiffstats
path: root/sqlglot/dialects
diff options
context:
space:
mode:
Diffstat (limited to 'sqlglot/dialects')
-rw-r--r--sqlglot/dialects/__init__.py2
-rw-r--r--sqlglot/dialects/bigquery.py1
-rw-r--r--sqlglot/dialects/clickhouse.py14
-rw-r--r--sqlglot/dialects/dialect.py6
-rw-r--r--sqlglot/dialects/doris.py6
-rw-r--r--sqlglot/dialects/duckdb.py84
-rw-r--r--sqlglot/dialects/hive.py5
-rw-r--r--sqlglot/dialects/materialize.py94
-rw-r--r--sqlglot/dialects/mysql.py6
-rw-r--r--sqlglot/dialects/postgres.py18
-rw-r--r--sqlglot/dialects/prql.py10
-rw-r--r--sqlglot/dialects/risingwave.py6
-rw-r--r--sqlglot/dialects/snowflake.py6
-rw-r--r--sqlglot/dialects/teradata.py6
-rw-r--r--sqlglot/dialects/tsql.py2
15 files changed, 234 insertions, 32 deletions
diff --git a/sqlglot/dialects/__init__.py b/sqlglot/dialects/__init__.py
index 29c6580..c85b607 100644
--- a/sqlglot/dialects/__init__.py
+++ b/sqlglot/dialects/__init__.py
@@ -70,12 +70,14 @@ from sqlglot.dialects.doris import Doris
from sqlglot.dialects.drill import Drill
from sqlglot.dialects.duckdb import DuckDB
from sqlglot.dialects.hive import Hive
+from sqlglot.dialects.materialize import Materialize
from sqlglot.dialects.mysql import MySQL
from sqlglot.dialects.oracle import Oracle
from sqlglot.dialects.postgres import Postgres
from sqlglot.dialects.presto import Presto
from sqlglot.dialects.prql import PRQL
from sqlglot.dialects.redshift import Redshift
+from sqlglot.dialects.risingwave import RisingWave
from sqlglot.dialects.snowflake import Snowflake
from sqlglot.dialects.spark import Spark
from sqlglot.dialects.spark2 import Spark2
diff --git a/sqlglot/dialects/bigquery.py b/sqlglot/dialects/bigquery.py
index 47fb0ce..d3db319 100644
--- a/sqlglot/dialects/bigquery.py
+++ b/sqlglot/dialects/bigquery.py
@@ -705,7 +705,6 @@ class BigQuery(Dialect):
# from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords
RESERVED_KEYWORDS = {
- *generator.Generator.RESERVED_KEYWORDS,
"all",
"and",
"any",
diff --git a/sqlglot/dialects/clickhouse.py b/sqlglot/dialects/clickhouse.py
index 7615203..f5c4e30 100644
--- a/sqlglot/dialects/clickhouse.py
+++ b/sqlglot/dialects/clickhouse.py
@@ -367,7 +367,7 @@ class ClickHouse(Dialect):
**parser.Parser.QUERY_MODIFIER_PARSERS,
TokenType.SETTINGS: lambda self: (
"settings",
- self._advance() or self._parse_csv(self._parse_conjunction),
+ self._advance() or self._parse_csv(self._parse_assignment),
),
TokenType.FORMAT: lambda self: ("format", self._advance() or self._parse_id_var()),
}
@@ -388,15 +388,15 @@ class ClickHouse(Dialect):
"INDEX",
}
- def _parse_conjunction(self) -> t.Optional[exp.Expression]:
- this = super()._parse_conjunction()
+ def _parse_assignment(self) -> t.Optional[exp.Expression]:
+ this = super()._parse_assignment()
if self._match(TokenType.PLACEHOLDER):
return self.expression(
exp.If,
this=this,
- true=self._parse_conjunction(),
- false=self._match(TokenType.COLON) and self._parse_conjunction(),
+ true=self._parse_assignment(),
+ false=self._match(TokenType.COLON) and self._parse_assignment(),
)
return this
@@ -461,7 +461,7 @@ class ClickHouse(Dialect):
# WITH <expression> AS <identifier>
cte = self.expression(
exp.CTE,
- this=self._parse_conjunction(),
+ this=self._parse_assignment(),
alias=self._parse_table_alias(),
scalar=True,
)
@@ -592,7 +592,7 @@ class ClickHouse(Dialect):
) -> exp.IndexColumnConstraint:
# INDEX name1 expr TYPE type1(args) GRANULARITY value
this = self._parse_id_var()
- expression = self._parse_conjunction()
+ expression = self._parse_assignment()
index_type = self._match_text_seq("TYPE") and (
self._parse_function() or self._parse_var()
diff --git a/sqlglot/dialects/dialect.py b/sqlglot/dialects/dialect.py
index 0421e4e..aea792a 100644
--- a/sqlglot/dialects/dialect.py
+++ b/sqlglot/dialects/dialect.py
@@ -50,12 +50,14 @@ class Dialects(str, Enum):
DRILL = "drill"
DUCKDB = "duckdb"
HIVE = "hive"
+ MATERIALIZE = "materialize"
MYSQL = "mysql"
ORACLE = "oracle"
POSTGRES = "postgres"
PRESTO = "presto"
PRQL = "prql"
REDSHIFT = "redshift"
+ RISINGWAVE = "risingwave"
SNOWFLAKE = "snowflake"
SPARK = "spark"
SPARK2 = "spark2"
@@ -593,7 +595,9 @@ def inline_array_unless_query(self: Generator, expression: exp.Array) -> str:
def no_ilike_sql(self: Generator, expression: exp.ILike) -> str:
return self.like_sql(
- exp.Like(this=exp.Lower(this=expression.this), expression=expression.expression)
+ exp.Like(
+ this=exp.Lower(this=expression.this), expression=exp.Lower(this=expression.expression)
+ )
)
diff --git a/sqlglot/dialects/doris.py b/sqlglot/dialects/doris.py
index 5f156cc..9fb073e 100644
--- a/sqlglot/dialects/doris.py
+++ b/sqlglot/dialects/doris.py
@@ -26,6 +26,9 @@ class Doris(MySQL):
"TO_DATE": exp.TsOrDsToDate.from_arg_list,
}
+ FUNCTION_PARSERS = MySQL.Parser.FUNCTION_PARSERS.copy()
+ FUNCTION_PARSERS.pop("GROUP_CONCAT")
+
class Generator(MySQL.Generator):
LAST_DAY_SUPPORTS_DATE_PART = False
@@ -49,6 +52,9 @@ class Doris(MySQL):
exp.ArrayUniqueAgg: rename_func("COLLECT_SET"),
exp.CurrentTimestamp: lambda self, _: self.func("NOW"),
exp.DateTrunc: lambda self, e: self.func("DATE_TRUNC", e.this, unit_to_str(e)),
+ exp.GroupConcat: lambda self, e: self.func(
+ "GROUP_CONCAT", e.this, e.args.get("separator") or exp.Literal.string(",")
+ ),
exp.JSONExtractScalar: lambda self, e: self.func("JSON_EXTRACT", e.this, e.expression),
exp.Map: rename_func("ARRAY_MAP"),
exp.RegexpLike: rename_func("REGEXP"),
diff --git a/sqlglot/dialects/duckdb.py b/sqlglot/dialects/duckdb.py
index 24c2b38..1316460 100644
--- a/sqlglot/dialects/duckdb.py
+++ b/sqlglot/dialects/duckdb.py
@@ -341,7 +341,7 @@ class DuckDB(Dialect):
if self._match(TokenType.L_BRACE, advance=False):
return self.expression(exp.ToMap, this=self._parse_bracket())
- args = self._parse_wrapped_csv(self._parse_conjunction)
+ args = self._parse_wrapped_csv(self._parse_assignment)
return self.expression(exp.Map, keys=seq_get(args, 0), values=seq_get(args, 1))
def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
@@ -503,11 +503,93 @@ class DuckDB(Dialect):
exp.DataType.Type.VARBINARY: "BLOB",
exp.DataType.Type.ROWVERSION: "BLOB",
exp.DataType.Type.VARCHAR: "TEXT",
+ exp.DataType.Type.TIMESTAMPNTZ: "TIMESTAMP",
exp.DataType.Type.TIMESTAMP_S: "TIMESTAMP_S",
exp.DataType.Type.TIMESTAMP_MS: "TIMESTAMP_MS",
exp.DataType.Type.TIMESTAMP_NS: "TIMESTAMP_NS",
}
+ # https://github.com/duckdb/duckdb/blob/ff7f24fd8e3128d94371827523dae85ebaf58713/third_party/libpg_query/grammar/keywords/reserved_keywords.list#L1-L77
+ RESERVED_KEYWORDS = {
+ "array",
+ "analyse",
+ "union",
+ "all",
+ "when",
+ "in_p",
+ "default",
+ "create_p",
+ "window",
+ "asymmetric",
+ "to",
+ "else",
+ "localtime",
+ "from",
+ "end_p",
+ "select",
+ "current_date",
+ "foreign",
+ "with",
+ "grant",
+ "session_user",
+ "or",
+ "except",
+ "references",
+ "fetch",
+ "limit",
+ "group_p",
+ "leading",
+ "into",
+ "collate",
+ "offset",
+ "do",
+ "then",
+ "localtimestamp",
+ "check_p",
+ "lateral_p",
+ "current_role",
+ "where",
+ "asc_p",
+ "placing",
+ "desc_p",
+ "user",
+ "unique",
+ "initially",
+ "column",
+ "both",
+ "some",
+ "as",
+ "any",
+ "only",
+ "deferrable",
+ "null_p",
+ "current_time",
+ "true_p",
+ "table",
+ "case",
+ "trailing",
+ "variadic",
+ "for",
+ "on",
+ "distinct",
+ "false_p",
+ "not",
+ "constraint",
+ "current_timestamp",
+ "returning",
+ "primary",
+ "intersect",
+ "having",
+ "analyze",
+ "current_user",
+ "and",
+ "cast",
+ "symmetric",
+ "using",
+ "order",
+ "current_catalog",
+ }
+
UNWRAPPED_INTERVAL_VALUES = (exp.Literal, exp.Paren)
# DuckDB doesn't generally support CREATE TABLE .. properties
diff --git a/sqlglot/dialects/hive.py b/sqlglot/dialects/hive.py
index 48e032d..f79c274 100644
--- a/sqlglot/dialects/hive.py
+++ b/sqlglot/dialects/hive.py
@@ -29,6 +29,7 @@ from sqlglot.dialects.dialect import (
struct_extract_sql,
time_format,
timestrtotime_sql,
+ unit_to_str,
var_map_sql,
)
from sqlglot.transforms import (
@@ -318,6 +319,7 @@ class Hive(Dialect):
),
"TO_DATE": build_formatted_time(exp.TsOrDsToDate, "hive"),
"TO_JSON": exp.JSONFormat.from_arg_list,
+ "TRUNC": exp.TimestampTrunc.from_arg_list,
"UNBASE64": exp.FromBase64.from_arg_list,
"UNIX_TIMESTAMP": lambda args: build_formatted_time(exp.StrToUnix, "hive", True)(
args or [exp.CurrentTimestamp()]
@@ -415,7 +417,7 @@ class Hive(Dialect):
) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
return (
(
- self._parse_csv(self._parse_conjunction)
+ self._parse_csv(self._parse_assignment)
if self._match_set({TokenType.PARTITION_BY, TokenType.DISTRIBUTE_BY})
else []
),
@@ -548,6 +550,7 @@ class Hive(Dialect):
exp.TimeStrToDate: rename_func("TO_DATE"),
exp.TimeStrToTime: timestrtotime_sql,
exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"),
+ exp.TimestampTrunc: lambda self, e: self.func("TRUNC", e.this, unit_to_str(e)),
exp.TimeToStr: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)),
exp.TimeToUnix: rename_func("UNIX_TIMESTAMP"),
exp.ToBase64: rename_func("BASE64"),
diff --git a/sqlglot/dialects/materialize.py b/sqlglot/dialects/materialize.py
new file mode 100644
index 0000000..4534c21
--- /dev/null
+++ b/sqlglot/dialects/materialize.py
@@ -0,0 +1,94 @@
+from __future__ import annotations
+
+from sqlglot import exp
+from sqlglot.helper import seq_get
+from sqlglot.dialects.postgres import Postgres
+
+from sqlglot.tokens import TokenType
+from sqlglot.transforms import (
+ remove_unique_constraints,
+ ctas_with_tmp_tables_to_create_tmp_view,
+ preprocess,
+)
+import typing as t
+
+
+class Materialize(Postgres):
+ class Parser(Postgres.Parser):
+ NO_PAREN_FUNCTION_PARSERS = {
+ **Postgres.Parser.NO_PAREN_FUNCTION_PARSERS,
+ "MAP": lambda self: self._parse_map(),
+ }
+
+ LAMBDAS = {
+ **Postgres.Parser.LAMBDAS,
+ TokenType.FARROW: lambda self, expressions: self.expression(
+ exp.Kwarg, this=seq_get(expressions, 0), expression=self._parse_assignment()
+ ),
+ }
+
+ def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
+ return self._parse_field()
+
+ def _parse_map(self) -> exp.ToMap:
+ if self._match(TokenType.L_PAREN):
+ to_map = self.expression(exp.ToMap, this=self._parse_select())
+ self._match_r_paren()
+ return to_map
+
+ if not self._match(TokenType.L_BRACKET):
+ self.raise_error("Expecting [")
+
+ entries = [
+ exp.PropertyEQ(this=e.this, expression=e.expression)
+ for e in self._parse_csv(self._parse_lambda)
+ ]
+
+ if not self._match(TokenType.R_BRACKET):
+ self.raise_error("Expecting ]")
+
+ return self.expression(exp.ToMap, this=self.expression(exp.Struct, expressions=entries))
+
+ class Generator(Postgres.Generator):
+ SUPPORTS_CREATE_TABLE_LIKE = False
+
+ TRANSFORMS = {
+ **Postgres.Generator.TRANSFORMS,
+ exp.AutoIncrementColumnConstraint: lambda self, e: "",
+ exp.Create: preprocess(
+ [
+ remove_unique_constraints,
+ ctas_with_tmp_tables_to_create_tmp_view,
+ ]
+ ),
+ exp.GeneratedAsIdentityColumnConstraint: lambda self, e: "",
+ exp.OnConflict: lambda self, e: "",
+ exp.PrimaryKeyColumnConstraint: lambda self, e: "",
+ }
+ TRANSFORMS.pop(exp.ToMap)
+
+ def propertyeq_sql(self, expression: exp.PropertyEQ) -> str:
+ return self.binary(expression, "=>")
+
+ def datatype_sql(self, expression: exp.DataType) -> str:
+ if expression.is_type(exp.DataType.Type.LIST):
+ if expression.expressions:
+ return f"{self.expressions(expression, flat=True)} LIST"
+ return "LIST"
+
+ if expression.is_type(exp.DataType.Type.MAP) and len(expression.expressions) == 2:
+ key, value = expression.expressions
+ return f"MAP[{self.sql(key)} => {self.sql(value)}]"
+
+ return super().datatype_sql(expression)
+
+ def list_sql(self, expression: exp.List) -> str:
+ if isinstance(seq_get(expression.expressions, 0), exp.Select):
+ return self.func("LIST", seq_get(expression.expressions, 0))
+
+ return f"{self.normalize_func('LIST')}[{self.expressions(expression, flat=True)}]"
+
+ def tomap_sql(self, expression: exp.ToMap) -> str:
+ if isinstance(expression.this, exp.Select):
+ return self.func("MAP", expression.this)
+ return f"{self.normalize_func('MAP')}[{self.expressions(expression.this)}]"
diff --git a/sqlglot/dialects/mysql.py b/sqlglot/dialects/mysql.py
index 611c527..26c7ad2 100644
--- a/sqlglot/dialects/mysql.py
+++ b/sqlglot/dialects/mysql.py
@@ -279,6 +279,10 @@ class MySQL(Dialect):
**parser.Parser.CONJUNCTION,
TokenType.DAMP: exp.And,
TokenType.XOR: exp.Xor,
+ }
+
+ DISJUNCTION = {
+ **parser.Parser.DISJUNCTION,
TokenType.DPIPE: exp.Or,
}
@@ -625,7 +629,7 @@ class MySQL(Dialect):
)
def _parse_chr(self) -> t.Optional[exp.Expression]:
- expressions = self._parse_csv(self._parse_conjunction)
+ expressions = self._parse_csv(self._parse_assignment)
kwargs: t.Dict[str, t.Any] = {"this": seq_get(expressions, 0)}
if len(expressions) > 1:
diff --git a/sqlglot/dialects/postgres.py b/sqlglot/dialects/postgres.py
index 249a04c..25a02b0 100644
--- a/sqlglot/dialects/postgres.py
+++ b/sqlglot/dialects/postgres.py
@@ -114,15 +114,6 @@ def _string_agg_sql(self: Postgres.Generator, expression: exp.GroupConcat) -> st
return f"STRING_AGG({self.format_args(this, separator)}{order})"
-def _datatype_sql(self: Postgres.Generator, expression: exp.DataType) -> str:
- if expression.is_type("array"):
- if expression.expressions:
- values = self.expressions(expression, key="values", flat=True)
- return f"{self.expressions(expression, flat=True)}[{values}]"
- return "ARRAY"
- return self.datatype_sql(expression)
-
-
def _auto_increment_to_serial(expression: exp.Expression) -> exp.Expression:
auto = expression.find(exp.AutoIncrementColumnConstraint)
@@ -500,7 +491,6 @@ class Postgres(Dialect):
exp.DateAdd: _date_add_sql("+"),
exp.DateDiff: _date_diff_sql,
exp.DateStrToDate: datestrtodate_sql,
- exp.DataType: _datatype_sql,
exp.DateSub: _date_add_sql("-"),
exp.Explode: rename_func("UNNEST"),
exp.GroupConcat: _string_agg_sql,
@@ -623,3 +613,11 @@ class Postgres(Dialect):
option = self.sql(expression, "option")
return f"SET {exprs}{access_method}{tablespace}{option}"
+
+ def datatype_sql(self, expression: exp.DataType) -> str:
+ if expression.is_type(exp.DataType.Type.ARRAY):
+ if expression.expressions:
+ values = self.expressions(expression, key="values", flat=True)
+ return f"{self.expressions(expression, flat=True)}[{values}]"
+ return "ARRAY"
+ return super().datatype_sql(expression)
diff --git a/sqlglot/dialects/prql.py b/sqlglot/dialects/prql.py
index ad0c647..2fc2594 100644
--- a/sqlglot/dialects/prql.py
+++ b/sqlglot/dialects/prql.py
@@ -36,6 +36,10 @@ class PRQL(Dialect):
CONJUNCTION = {
**parser.Parser.CONJUNCTION,
TokenType.DAMP: exp.And,
+ }
+
+ DISJUNCTION = {
+ **parser.Parser.DISJUNCTION,
TokenType.DPIPE: exp.Or,
}
@@ -43,7 +47,7 @@ class PRQL(Dialect):
"DERIVE": lambda self, query: self._parse_selection(query),
"SELECT": lambda self, query: self._parse_selection(query, append=False),
"TAKE": lambda self, query: self._parse_take(query),
- "FILTER": lambda self, query: query.where(self._parse_conjunction()),
+ "FILTER": lambda self, query: query.where(self._parse_assignment()),
"APPEND": lambda self, query: query.union(
_select_all(self._parse_table()), distinct=False, copy=False
),
@@ -174,8 +178,8 @@ class PRQL(Dialect):
if self._next and self._next.token_type == TokenType.ALIAS:
alias = self._parse_id_var(True)
self._match(TokenType.ALIAS)
- return self.expression(exp.Alias, this=self._parse_conjunction(), alias=alias)
- return self._parse_conjunction()
+ return self.expression(exp.Alias, this=self._parse_assignment(), alias=alias)
+ return self._parse_assignment()
def _parse_table(
self,
diff --git a/sqlglot/dialects/risingwave.py b/sqlglot/dialects/risingwave.py
new file mode 100644
index 0000000..18906aa
--- /dev/null
+++ b/sqlglot/dialects/risingwave.py
@@ -0,0 +1,6 @@
+from sqlglot.dialects.postgres import Postgres
+
+
+class RisingWave(Postgres):
+ class Generator(Postgres.Generator):
+ LOCKING_READS_SUPPORTED = False
diff --git a/sqlglot/dialects/snowflake.py b/sqlglot/dialects/snowflake.py
index f72b29e..8c3c471 100644
--- a/sqlglot/dialects/snowflake.py
+++ b/sqlglot/dialects/snowflake.py
@@ -498,7 +498,7 @@ class Snowflake(Dialect):
TokenType.ARROW: lambda self, expressions: self.expression(
exp.Lambda,
this=self._replace_lambda(
- self._parse_conjunction(),
+ self._parse_assignment(),
expressions,
),
expressions=[e.this if isinstance(e, exp.Cast) else e for e in expressions],
@@ -576,7 +576,7 @@ class Snowflake(Dialect):
# - https://docs.snowflake.com/en/sql-reference/functions/object_construct
return self._parse_slice(self._parse_string())
- return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
+ return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
def _parse_lateral(self) -> t.Optional[exp.Lateral]:
lateral = super()._parse_lateral()
@@ -714,7 +714,7 @@ class Snowflake(Dialect):
def _parse_file_location(self) -> t.Optional[exp.Expression]:
# Parse either a subquery or a staged file
return (
- self._parse_select(table=True)
+ self._parse_select(table=True, parse_subquery_alias=False)
if self._match(TokenType.L_PAREN, advance=False)
else self._parse_table_parts()
)
diff --git a/sqlglot/dialects/teradata.py b/sqlglot/dialects/teradata.py
index feb2097..90a0bf4 100644
--- a/sqlglot/dialects/teradata.py
+++ b/sqlglot/dialects/teradata.py
@@ -164,7 +164,7 @@ class Teradata(Dialect):
}
def _parse_translate(self, strict: bool) -> exp.Expression:
- this = self._parse_conjunction()
+ this = self._parse_assignment()
if not self._match(TokenType.USING):
self.raise_error("Expected USING in TRANSLATE")
@@ -195,8 +195,8 @@ class Teradata(Dialect):
this = self._parse_id_var()
self._match(TokenType.BETWEEN)
- expressions = self._parse_csv(self._parse_conjunction)
- each = self._match_text_seq("EACH") and self._parse_conjunction()
+ expressions = self._parse_csv(self._parse_assignment)
+ each = self._match_text_seq("EACH") and self._parse_assignment()
return self.expression(exp.RangeN, this=this, expressions=expressions, each=each)
diff --git a/sqlglot/dialects/tsql.py b/sqlglot/dialects/tsql.py
index f1a61dd..ee403a7 100644
--- a/sqlglot/dialects/tsql.py
+++ b/sqlglot/dialects/tsql.py
@@ -625,7 +625,7 @@ class TSQL(Dialect):
) -> t.Optional[exp.Expression]:
this = self._parse_types()
self._match(TokenType.COMMA)
- args = [this, *self._parse_csv(self._parse_conjunction)]
+ args = [this, *self._parse_csv(self._parse_assignment)]
convert = exp.Convert.from_arg_list(args)
convert.set("safe", safe)
convert.set("strict", strict)