diff --git a/.all-contributorsrc b/.all-contributorsrc
index 02a86f1818..92b95c9c8c 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -7645,6 +7645,15 @@
"contributions": [
"bug"
]
+ },
+ {
+ "login": "duursma",
+ "name": "duursma",
+ "avatar_url": "https://avatars.githubusercontent.com/u/9378973?v=4",
+ "profile": "https://github.com/duursma",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md
index 97c0ea98da..d9cffe897d 100644
--- a/docs/pages/pmd/projectdocs/credits.md
+++ b/docs/pages/pmd/projectdocs/credits.md
@@ -891,198 +891,201 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
 dreaminpast123 ๐ |
 duanyanan ๐ |
 dutt-sanjay ๐ |
+  duursma ๐ป |
 dylanleung ๐ |
 dzeigler ๐ |
 eant60 ๐ |
-  ekkirala ๐ |
+  ekkirala ๐ |
 emersonmoura ๐ |
 emouty ๐ป |
 eugenepugach ๐ |
 fairy ๐ |
 filiprafalowicz ๐ป |
 flxbl-io ๐ต |
-  foxmason ๐ |
+  foxmason ๐ |
 frankegabor ๐ |
 frankl ๐ |
 freafrea ๐ |
 fsapatin ๐ |
 gracia19 ๐ |
 guo fei ๐ |
-  gurmsc5 ๐ |
+  gurmsc5 ๐ |
 gwilymatgearset ๐ป ๐ |
 haigsn ๐ |
 hemanshu070 ๐ |
 henrik242 ๐ |
 hongpuwu ๐ |
 hvbtup ๐ป ๐ |
-  igniti GmbH ๐ |
+  igniti GmbH ๐ |
 ilovezfs ๐ |
 itaigilo ๐ |
 jakivey32 ๐ |
 jbennett2091 ๐ |
 jcamerin ๐ |
 jkeener1 ๐ |
-  jmetertea ๐ |
+  jmetertea ๐ |
 johnra2 ๐ป |
 johnzhao9 ๐ |
 josemanuelrolon ๐ป ๐ |
 kabroxiko ๐ป ๐ |
 karwer ๐ |
 kaulonline ๐ |
-  kdaemonv ๐ |
+  kdaemonv ๐ |
 kdebski85 ๐ ๐ป |
 kenji21 ๐ป ๐ |
 kfranic ๐ |
 khalidkh ๐ |
 koalalam ๐ |
 krzyk ๐ |
-  lasselindqvist ๐ |
+  lasselindqvist ๐ |
 lgemeinhardt ๐ |
 lihuaib ๐ |
 liqingjun123 ๐ |
 lonelyma1021 ๐ |
 lpeddy ๐ |
 lujiefsi ๐ป |
-  lukelukes ๐ป |
+  lukelukes ๐ป |
 lyriccoder ๐ |
 marcelmore ๐ |
 matchbox ๐ |
 matthiaskraaz ๐ |
 meandonlyme ๐ |
 mikesive ๐ |
-  milossesic ๐ |
+  milossesic ๐ |
 mluckam ๐ป ๐ |
 mohan-chinnappan-n ๐ป |
 mriddell95 ๐ |
 mrlzh ๐ |
 msloan ๐ |
 mucharlaravalika ๐ |
-  mvenneman ๐ |
+  mvenneman ๐ |
 nareshl119 ๐ |
 nicolas-harraudeau-sonarsource ๐ |
 noerremark ๐ |
 novsirion ๐ |
 nwcm ๐ ๐ ๐ป |
 oggboy ๐ |
-  oinume ๐ |
+  oinume ๐ |
 orimarko ๐ป ๐ |
 pablogomez2197 ๐ |
 pacvz ๐ป |
 pallavi agarwal ๐ |
 parksungrin ๐ |
 patpatpat123 ๐ |
-  patriksevallius ๐ |
+  patriksevallius ๐ |
 pbrajesh1 ๐ |
 phoenix384 ๐ |
 piotrszymanski-sc ๐ป |
 plan3d ๐ |
 poojasix ๐ |
 prabhushrikant ๐ |
-  pujitha8783 ๐ |
+  pujitha8783 ๐ |
 r-r-a-j ๐ |
 raghujayjunk ๐ |
 rajeshveera ๐ |
 rajeswarreddy88 ๐ |
 recdevs ๐ |
 reudismam ๐ป ๐ |
-  rijkt ๐ |
+  rijkt ๐ |
 rillig-tk ๐ |
 rmohan20 ๐ป ๐ |
 rnveach ๐ |
 rxmicro ๐ |
 ryan-gustafson ๐ป ๐ |
 sabi0 ๐ |
-  scais ๐ |
+  scais ๐ |
 screamingfrog ๐ต |
 sebbASF ๐ |
 sergeygorbaty ๐ป |
 shilko2013 ๐ |
 shiomiyan ๐ |
 simeonKondr ๐ |
-  snajberk ๐ |
+  snajberk ๐ |
 sniperrifle2004 ๐ |
 snuyanzin ๐ ๐ป |
 soyodream ๐ |
 sratz ๐ |
 stonio ๐ |
 sturton ๐ป ๐ |
-  sudharmohan ๐ |
+  sudharmohan ๐ |
 suruchidawar ๐ |
 svenfinitiv ๐ |
 szymanp23 ๐ ๐ป |
 tashiscool ๐ |
 test-git-hook ๐ |
 testation21 ๐ป ๐ |
-  thanosa ๐ |
+  thanosa ๐ |
 tiandiyixian ๐ |
 tobwoerk ๐ |
 tprouvot ๐ ๐ป |
 trentchilders ๐ |
 triandicAnt ๐ |
 trishul14 ๐ |
-  tsui ๐ |
+  tsui ๐ |
 wangzitom12306 ๐ |
 winhkey ๐ |
 witherspore ๐ |
 wjljack ๐ |
 wuchiuwong ๐ |
 xingsong ๐ |
-  xioayuge ๐ |
+  xioayuge ๐ |
 xnYi9wRezm ๐ป ๐ |
 xuanuy ๐ |
 xyf0921 ๐ |
 yalechen-cyw3 ๐ |
 yasuharu-sato ๐ |
 zenglian ๐ |
-  zgrzyt93 ๐ป ๐ |
+  zgrzyt93 ๐ป ๐ |
 zh3ng ๐ |
 zt_soft ๐ |
 ztt79 ๐ |
 zzzzfeng ๐ |
 รrpรกd Magosรกnyi ๐ |
 ไปป่ดตๆฐ ๐ |
+
+
 ่
ๅปถๅฎ ๐ป |
diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md
index bc1a36ec7a..68fffd2835 100644
--- a/docs/pages/release_notes.md
+++ b/docs/pages/release_notes.md
@@ -15,10 +15,13 @@ This is a {{ site.pmd.release_type }} release.
### ๐ New and noteworthy
### ๐ Fixed Issues
+* plsql
+ * [#5086](https://github.com/pmd/pmd/pull/5086): \[plsql] Fixed issue with missing optional table alias in MERGE usage
### ๐จ API Changes
### โจ External Contributions
+* [#5086](https://github.com/pmd/pmd/pull/5086): \[plsql] Fixed issue with missing optional table alias in MERGE usage - [Arjen Duursma](https://github.com/duursma) (@duursma)
{% endtocmaker %}
diff --git a/pmd-plsql/etc/grammar/PLSQL.jjt b/pmd-plsql/etc/grammar/PLSQL.jjt
index e1b14b3992..daf6f68f31 100644
--- a/pmd-plsql/etc/grammar/PLSQL.jjt
+++ b/pmd-plsql/etc/grammar/PLSQL.jjt
@@ -2709,7 +2709,7 @@ ASTDeleteStatement DeleteStatement() :
ASTMergeStatement MergeStatement() :
{}
{
- [ LOOKAHEAD(2) SchemaName() "." ] TableName() [ TableAlias() ]
+ [ LOOKAHEAD(2) SchemaName() "." ] TableName() [ LOOKAHEAD(1, ID(), { getToken(1).kind != USING } ) TableAlias() ]
(
LOOKAHEAD(3) "(" ValuesClause() ")"
diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.pls
index 555f439f0b..782d8cffba 100644
--- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.pls
+++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.pls
@@ -13,5 +13,13 @@ BEGIN
THEN UPDATE SET b.text = e.text
WHEN NOT MATCHED
THEN INSERT (ID,KEY1, TEXT,LCE_ID) values (JHS_SEQ.NEXTVAL,'PROM_EDIT_PROM_NR','Edycja promocji nr',123123);
+
+ MERGE INTO b
+ USING ( SELECT 'PROM_EDIT_PROM_NR' key1,'Edycja promocji nr' text,123123 lce_id FROM dual ) e
+ ON (b.key1 = e.key1 and b.lce_id=e.lce_id)
+ WHEN MATCHED
+ THEN UPDATE SET b.text = e.text
+ WHEN NOT MATCHED
+ THEN INSERT (ID,KEY1, TEXT,LCE_ID) values (JHS_SEQ.NEXTVAL,'PROM_EDIT_PROM_NR','Edycja promocji nr',123123);
END;
/
diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.txt
index c473d6143c..bda27d276c 100644
--- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.txt
+++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/MergeStatementIssue1934.txt
@@ -1,12 +1,115 @@
+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0]
+- Global[@CanonicalImage = null]
+- Block[@CanonicalImage = null]
+ +- Statement[@CanonicalImage = null]
+ | +- UnlabelledStatement[@CanonicalImage = null]
+ | +- MergeStatement[@CanonicalImage = null]
+ | +- TableName[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
+ | | +- ID[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
+ | +- TableAlias[@CanonicalImage = "B", @Image = "b"]
+ | | +- ID[@CanonicalImage = "B", @Image = "b"]
+ | +- QueryBlock[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false]
+ | | +- SelectList[@CanonicalImage = null]
+ | | | +- SqlExpression[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
+ | | | | +- PrimaryPrefix[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @SelfModifier = false]
+ | | | | +- Literal[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
+ | | | | +- StringLiteral[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @String = "PROM_EDIT_PROM_NR"]
+ | | | +- ColumnAlias[@CanonicalImage = "KEY1", @Image = "key1"]
+ | | | | +- ID[@CanonicalImage = "KEY1", @Image = "key1"]
+ | | | +- SqlExpression[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
+ | | | | +- PrimaryPrefix[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @SelfModifier = false]
+ | | | | +- Literal[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
+ | | | | +- StringLiteral[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @String = "Edycja promocji nr"]
+ | | | +- ColumnAlias[@CanonicalImage = "TEXT", @Image = "text"]
+ | | | | +- ID[@CanonicalImage = "TEXT", @Image = "text"]
+ | | | +- SqlExpression[@CanonicalImage = "123123", @Image = "123123"]
+ | | | | +- PrimaryPrefix[@CanonicalImage = "123123", @Image = "123123", @SelfModifier = false]
+ | | | | +- Literal[@CanonicalImage = "123123", @Image = "123123"]
+ | | | | +- NumericLiteral[@CanonicalImage = "123123", @Image = "123123"]
+ | | | +- ColumnAlias[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
+ | | | +- ID[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
+ | | +- FromClause[@CanonicalImage = null]
+ | | +- TableReference[@CanonicalImage = null]
+ | | +- TableName[@CanonicalImage = "DUAL", @Image = "dual"]
+ | | +- ID[@CanonicalImage = "DUAL", @Image = "dual"]
+ | +- TableAlias[@CanonicalImage = "E", @Image = "e"]
+ | | +- ID[@CanonicalImage = "E", @Image = "e"]
+ | +- Condition[@CanonicalImage = null]
+ | | +- CompoundCondition[@CanonicalImage = null, @Type = "AND"]
+ | | +- ComparisonCondition[@CanonicalImage = null, @Operator = "="]
+ | | | +- SqlExpression[@CanonicalImage = "B.KEY1", @Image = "b.key1"]
+ | | | | +- PrimaryPrefix[@CanonicalImage = "B.KEY1", @Image = "b.key1", @SelfModifier = false]
+ | | | | +- SimpleExpression[@CanonicalImage = "B.KEY1", @Image = "b.key1"]
+ | | | | +- TableName[@CanonicalImage = "B", @Image = "b"]
+ | | | | | +- ID[@CanonicalImage = "B", @Image = "b"]
+ | | | | +- Column[@CanonicalImage = "KEY1", @Image = "key1"]
+ | | | | +- ID[@CanonicalImage = "KEY1", @Image = "key1"]
+ | | | +- SqlExpression[@CanonicalImage = "E.KEY1", @Image = "e.key1"]
+ | | | +- PrimaryPrefix[@CanonicalImage = "E.KEY1", @Image = "e.key1", @SelfModifier = false]
+ | | | +- SimpleExpression[@CanonicalImage = "E.KEY1", @Image = "e.key1"]
+ | | | +- TableName[@CanonicalImage = "E", @Image = "e"]
+ | | | | +- ID[@CanonicalImage = "E", @Image = "e"]
+ | | | +- Column[@CanonicalImage = "KEY1", @Image = "key1"]
+ | | | +- ID[@CanonicalImage = "KEY1", @Image = "key1"]
+ | | +- Condition[@CanonicalImage = null]
+ | | +- CompoundCondition[@CanonicalImage = null, @Type = null]
+ | | +- ComparisonCondition[@CanonicalImage = null, @Operator = "="]
+ | | +- SqlExpression[@CanonicalImage = "B.LCE_ID", @Image = "b.lce_id"]
+ | | | +- PrimaryPrefix[@CanonicalImage = "B.LCE_ID", @Image = "b.lce_id", @SelfModifier = false]
+ | | | +- SimpleExpression[@CanonicalImage = "B.LCE_ID", @Image = "b.lce_id"]
+ | | | +- TableName[@CanonicalImage = "B", @Image = "b"]
+ | | | | +- ID[@CanonicalImage = "B", @Image = "b"]
+ | | | +- Column[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
+ | | | +- ID[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
+ | | +- SqlExpression[@CanonicalImage = "E.LCE_ID", @Image = "e.lce_id"]
+ | | +- PrimaryPrefix[@CanonicalImage = "E.LCE_ID", @Image = "e.lce_id", @SelfModifier = false]
+ | | +- SimpleExpression[@CanonicalImage = "E.LCE_ID", @Image = "e.lce_id"]
+ | | +- TableName[@CanonicalImage = "E", @Image = "e"]
+ | | | +- ID[@CanonicalImage = "E", @Image = "e"]
+ | | +- Column[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
+ | | +- ID[@CanonicalImage = "LCE_ID", @Image = "lce_id"]
+ | +- MergeUpdateClause[@CanonicalImage = null]
+ | | +- TableName[@CanonicalImage = "B", @Image = "b"]
+ | | | +- ID[@CanonicalImage = "B", @Image = "b"]
+ | | +- Column[@CanonicalImage = "TEXT", @Image = "text"]
+ | | | +- ID[@CanonicalImage = "TEXT", @Image = "text"]
+ | | +- Expression[@CanonicalImage = "E.TEXT", @Image = "e.text"]
+ | | +- PrimaryPrefix[@CanonicalImage = "E.TEXT", @Image = "e.text", @SelfModifier = false]
+ | | +- SimpleExpression[@CanonicalImage = "E.TEXT", @Image = "e.text"]
+ | | +- TableName[@CanonicalImage = "E", @Image = "e"]
+ | | | +- ID[@CanonicalImage = "E", @Image = "e"]
+ | | +- Column[@CanonicalImage = "TEXT", @Image = "text"]
+ | | +- ID[@CanonicalImage = "TEXT", @Image = "text"]
+ | +- MergeInsertClause[@CanonicalImage = null]
+ | +- Column[@CanonicalImage = "ID", @Image = "ID"]
+ | | +- ID[@CanonicalImage = "ID", @Image = "ID"]
+ | +- Column[@CanonicalImage = "KEY1", @Image = "KEY1"]
+ | | +- ID[@CanonicalImage = "KEY1", @Image = "KEY1"]
+ | +- Column[@CanonicalImage = "TEXT", @Image = "TEXT"]
+ | | +- ID[@CanonicalImage = "TEXT", @Image = "TEXT"]
+ | +- Column[@CanonicalImage = "LCE_ID", @Image = "LCE_ID"]
+ | | +- ID[@CanonicalImage = "LCE_ID", @Image = "LCE_ID"]
+ | +- ValuesClause[@CanonicalImage = null]
+ | +- Expression[@CanonicalImage = "", @Image = ""]
+ | | +- PrimaryPrefix[@CanonicalImage = "", @Image = "", @SelfModifier = false]
+ | | +- SimpleExpression[@CanonicalImage = "", @Image = ""]
+ | | +- ID[@CanonicalImage = "JHS_SEQ", @Image = "JHS_SEQ"]
+ | +- Expression[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
+ | | +- PrimaryPrefix[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @SelfModifier = false]
+ | | +- Literal[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'"]
+ | | +- StringLiteral[@CanonicalImage = "\'PROM_EDIT_PROM_NR\'", @Image = "\'PROM_EDIT_PROM_NR\'", @String = "PROM_EDIT_PROM_NR"]
+ | +- Expression[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
+ | | +- PrimaryPrefix[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @SelfModifier = false]
+ | | +- Literal[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'"]
+ | | +- StringLiteral[@CanonicalImage = "\'EDYCJA PROMOCJI NR\'", @Image = "\'Edycja promocji nr\'", @String = "Edycja promocji nr"]
+ | +- Expression[@CanonicalImage = "123123", @Image = "123123"]
+ | +- PrimaryPrefix[@CanonicalImage = "123123", @Image = "123123", @SelfModifier = false]
+ | +- Literal[@CanonicalImage = "123123", @Image = "123123"]
+ | +- NumericLiteral[@CanonicalImage = "123123", @Image = "123123"]
+- Statement[@CanonicalImage = null]
+- UnlabelledStatement[@CanonicalImage = null]
+- MergeStatement[@CanonicalImage = null]
- +- TableName[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
- | +- ID[@CanonicalImage = "JHS_TRANSLATIONS", @Image = "jhs_translations"]
- +- TableAlias[@CanonicalImage = "B", @Image = "b"]
+ +- TableName[@CanonicalImage = "B", @Image = "b"]
| +- ID[@CanonicalImage = "B", @Image = "b"]
+- QueryBlock[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false]
| +- SelectList[@CanonicalImage = null]