Skip to content
Merged
1 change: 1 addition & 0 deletions sqlglot/expressions/dml.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class Insert(Expression, DDL, DML):
"settings": False,
"source": False,
"default": False,
"using": False,
}

def with_(
Expand Down
4 changes: 3 additions & 1 deletion sqlglot/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2283,6 +2283,8 @@ def insert_sql(self, expression: exp.Insert) -> str:
exists = " IF EXISTS" if expression.args.get("exists") else ""
where = self.sql(expression, "where")
where = f"{self.sep()}REPLACE WHERE {where}" if where else ""
using = self.expressions(expression, key="using", flat=True)
using = f"{self.sep()}REPLACE USING ({using})" if using else ""
expression_sql = f"{self.sep()}{self.sql(expression, 'expression')}"
on_conflict = self.sql(expression, "conflict")
on_conflict = f" {on_conflict}" if on_conflict else ""
Expand All @@ -2303,7 +2305,7 @@ def insert_sql(self, expression: exp.Insert) -> str:
source = self.sql(expression, "source")
source = f"TABLE {source}" if source else ""

sql = f"INSERT{hint}{alternative}{ignore}{this}{stored}{by_name}{exists}{partition_by}{settings}{where}{expression_sql}{source}"
sql = f"INSERT{hint}{alternative}{ignore}{this}{stored}{by_name}{exists}{partition_by}{settings}{where}{using}{expression_sql}{source}"
return self.prepend_ctes(expression, sql)

def introducer_sql(self, expression: exp.Introducer) -> str:
Expand Down
22 changes: 17 additions & 5 deletions sqlglot/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3598,16 +3598,28 @@ def _parse_set_assignment() -> exp.Expr | None:

returning = self._parse_returning() # TSQL allows RETURNING before source

stored = self._match_text_seq("STORED") and self._parse_stored()
by_name = self._match_text_seq("BY", "NAME")
exists = self._parse_exists()
replace_where = None
replace_using = None

if self._match(TokenType.REPLACE):
if self._match(TokenType.WHERE):
replace_where = self._parse_disjunction()
elif self._match(TokenType.USING):
replace_using = self._parse_using_identifiers()

return self.expression(
exp.Insert(
hint=hint,
is_function=is_function,
this=this,
stored=self._match_text_seq("STORED") and self._parse_stored(),
by_name=self._match_text_seq("BY", "NAME"),
exists=self._parse_exists(),
where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
and self._parse_disjunction(),
stored=stored,
by_name=by_name,
exists=exists,
where=replace_where,
using=replace_using,
partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
default=self._match_text_seq("DEFAULT", "VALUES"),
Expand Down
5 changes: 5 additions & 0 deletions tests/dialects/test_databricks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
class TestDatabricks(Validator):
dialect = "databricks"

def test_insert_replace_using(self):
self.validate_identity(
"INSERT INTO target REPLACE USING (c1, c2) SELECT c1, c2 FROM source"
)

def test_databricks(self):
self.validate_identity("CREATE TABLE foo (my_arr ARRAY<STRING COLLATE UTF8_BINARY>)")
self.validate_identity("CREATE TABLE foo (m MAP<STRING, STRING COLLATE UTF8_BINARY>)")
Expand Down
Loading