Repository: AlecStrong/sql-psi (kotlin)

Issue:
PostgreSQL column-list syntax
Dialect: PostgreSQL

failing sql:

```sql
update:
    UPDATE lastSeen SET (userid, timestamp) = (:userid, :timestamp)
    WHERE lastSeen.account = :account AND lastSeen.username = :username
;
```

example from postgresql docs:

```sql
UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT)
  WHERE city = 'San Francisco' AND date = '2003-07-03';
```

Pull request:
Closes https://github.com/AlecStrong/sql-psi/issues/159

Patch:
diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/sql.bnf b/core/src/main/kotlin/com/alecstrong/sql/psi/core/sql.bnf
index a7d16703..b4c3f2ef 100644
--- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/sql.bnf
+++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/sql.bnf
@@ -369,11 +369,17 @@ compound_operator ::= ( UNION ALL
                       | UNION
                       | INTERSECT
                       | EXCEPT )
-update_stmt ::= [ with_clause ] UPDATE [ OR ROLLBACK | OR ABORT | OR REPLACE | OR FAIL | OR IGNORE ] qualified_table_name SET column_name '=' setter_expression update_stmt_subsequent_setter * [ WHERE expr ] {
+update_stmt ::= [ with_clause ] UPDATE [ OR ROLLBACK | OR ABORT | OR REPLACE | OR FAIL | OR IGNORE ] qualified_table_name
+  SET (( column_name '=' setter_expression update_stmt_subsequent_setter * ) | ( '(' column_name ( ',' column_name ) * ')' ) '=' ( '(' setter_expression ( ',' setter_expression ) * ')' ))
+  [ WHERE expr ] {
   mixin = "com.alecstrong.sql.psi.core.psi.mixins.MutatorMixin"
   pin = 4
 }
-update_stmt_limited ::= [ with_clause ] UPDATE [ OR ROLLBACK | OR ABORT | OR REPLACE | OR FAIL | OR IGNORE ] qualified_table_name SET column_name '=' setter_expression update_stmt_subsequent_setter * [ WHERE expr ] [ [ ORDER BY ordering_term ( ',' ordering_term ) * ] LIMIT expr [ ( OFFSET | ',' ) expr ] ] {
+update_stmt_limited ::= [ with_clause ] UPDATE [ OR ROLLBACK | OR ABORT | OR REPLACE | OR FAIL | OR IGNORE ] qualified_table_name
+  SET (( column_name '=' setter_expression update_stmt_subsequent_setter * ) | ( '(' column_name ( ',' column_name ) * ')' ) '=' ( '(' setter_expression ( ',' setter_expression ) * ')' ))
+  [ WHERE expr ]
+  [ [ ORDER BY ordering_term ( ',' ordering_term ) * ]
+  LIMIT expr [ ( OFFSET | ',' ) expr ] ] {
   mixin = "com.alecstrong.sql.psi.core.psi.mixins.MutatorMixin"
   pin = 4
 }
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 7cf81802..8c5aa188 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -14,5 +14,5 @@ kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
 grammarKitComposer = { id = "com.alecstrong.grammar.kit.composer", version = "0.1.7" }
 spotless = { id = "com.diffplug.spotless", version = "6.4.2" }
 mavenPublish = { id = "com.vanniktech.maven.publish", version = "0.19.0" }
-dokka = { id = "org.jetbrains.dokka", version.ref = "1.6.10" }
+dokka = { id = "org.jetbrains.dokka", version = "1.6.10" }
 intellij = { id = "org.jetbrains.intellij", version = "1.5.2" }


Test patch:
diff --git a/test-fixtures/src/main/resources/fixtures/update-multiple-columns/Test.s b/test-fixtures/src/main/resources/fixtures/update-multiple-columns/Test.s
new file mode 100644
index 00000000..e41a4935
--- /dev/null
+++ b/test-fixtures/src/main/resources/fixtures/update-multiple-columns/Test.s
@@ -0,0 +1,8 @@
+CREATE TABLE test(
+  text1 TEXT,
+  text2 TEXT,
+  text3 TEXT
+);
+
+UPDATE test
+SET (text1, text2, text3) = ('one', 'two', 'three');
\ No newline at end of file