Skip to content

Commit 72781ef

Browse files
authored
Escape JIRA reserved words in JqlQueryBuilder (#127)
1 parent f44830a commit 72781ef

File tree

2 files changed

+208
-1
lines changed

2 files changed

+208
-1
lines changed

src/main/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilder.java

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020

2121
import java.io.UnsupportedEncodingException;
2222
import java.net.URLEncoder;
23+
import java.util.Arrays;
2324
import java.util.List;
2425
import java.util.Locale;
2526

27+
import org.apache.commons.lang3.ArraySorter;
2628
import org.apache.maven.plugin.logging.Log;
2729

2830
/**
@@ -33,6 +35,190 @@
3335
* @since 2.8
3436
*/
3537
public class JqlQueryBuilder {
38+
39+
/**
40+
* JQL <a href="https://confluence.atlassian.com/gsgtest/advanced-searching-815566220.html">reserved words</a>.
41+
*/
42+
private static final String[] RESERVED_JQL_WORDS = ArraySorter.sort(new String[] {
43+
"abort",
44+
"access",
45+
"add",
46+
"after",
47+
"alias",
48+
"all",
49+
"alter",
50+
"and",
51+
"any",
52+
"as",
53+
"asc",
54+
"audit",
55+
"avg",
56+
"before",
57+
"begin",
58+
"between",
59+
"boolean",
60+
"break",
61+
"by",
62+
"byte",
63+
"catch",
64+
"cf",
65+
"char",
66+
"character",
67+
"check",
68+
"checkpoint",
69+
"collate",
70+
"collation",
71+
"column",
72+
"commit",
73+
"connect",
74+
"continue",
75+
"count",
76+
"create",
77+
"current",
78+
"date",
79+
"decimal",
80+
"declare",
81+
"decrement",
82+
"default",
83+
"defaults",
84+
"define",
85+
"delete",
86+
"delimiter",
87+
"desc",
88+
"difference",
89+
"distinct",
90+
"divide",
91+
"do",
92+
"double",
93+
"drop",
94+
"else",
95+
"empty",
96+
"encoding",
97+
"end",
98+
"equals",
99+
"escape",
100+
"exclusive",
101+
"exec",
102+
"execute",
103+
"exists",
104+
"explain",
105+
"false",
106+
"fetch",
107+
"file",
108+
"field",
109+
"first",
110+
"float",
111+
"for",
112+
"from",
113+
"function",
114+
"go",
115+
"goto",
116+
"grant",
117+
"greater",
118+
"group",
119+
"having",
120+
"identified",
121+
"if",
122+
"immediate",
123+
"in",
124+
"increment",
125+
"index",
126+
"initial",
127+
"inner",
128+
"inout",
129+
"input",
130+
"insert",
131+
"int",
132+
"integer",
133+
"intersect",
134+
"intersection",
135+
"into",
136+
"is",
137+
"isempty",
138+
"isnull",
139+
"join",
140+
"last",
141+
"left",
142+
"less",
143+
"like",
144+
"limit",
145+
"lock",
146+
"long",
147+
"max",
148+
"min",
149+
"minus",
150+
"mode",
151+
"modify",
152+
"modulo",
153+
"more",
154+
"multiply",
155+
"next",
156+
"noaudit",
157+
"not",
158+
"notin",
159+
"nowait",
160+
"null",
161+
"number",
162+
"object",
163+
"of",
164+
"on",
165+
"option",
166+
"or",
167+
"order",
168+
"outer",
169+
"output",
170+
"power",
171+
"previous",
172+
"prior",
173+
"privileges",
174+
"public",
175+
"raise",
176+
"raw",
177+
"remainder",
178+
"rename",
179+
"resource",
180+
"return",
181+
"returns",
182+
"revoke",
183+
"right",
184+
"row",
185+
"rowid",
186+
"rownum",
187+
"rows",
188+
"select",
189+
"session",
190+
"set",
191+
"share",
192+
"size",
193+
"sqrt",
194+
"start",
195+
"strict",
196+
"string",
197+
"subtract",
198+
"sum",
199+
"synonym",
200+
"table",
201+
"then",
202+
"to",
203+
"trans",
204+
"transaction",
205+
"trigger",
206+
"true",
207+
"uid",
208+
"union",
209+
"unique",
210+
"update",
211+
"user",
212+
"validate",
213+
"values",
214+
"view",
215+
"when",
216+
"whenever",
217+
"where",
218+
"while",
219+
"with"
220+
});
221+
36222
private String filter = "";
37223

38224
private boolean urlEncode = true;
@@ -265,10 +451,20 @@ private void addSingleValue(String key, String value) {
265451

266452
private void trimAndQuoteValue(String value) {
267453
String trimmedValue = value.trim();
268-
if (trimmedValue.contains(" ") || trimmedValue.contains(".")) {
454+
if (trimmedValue.contains(" ") || trimmedValue.contains(".") || isReservedJqlWord(trimmedValue)) {
269455
query.append("\"").append(trimmedValue).append("\"");
270456
} else {
271457
query.append(trimmedValue);
272458
}
273459
}
460+
461+
/**
462+
* JQL <a href="https://confluence.atlassian.com/gsgtest/advanced-searching-815566220.html">reserved words</a>.
463+
*
464+
* @param value a string
465+
* @return whether the given string is a JQL reserved word.
466+
*/
467+
private boolean isReservedJqlWord(String value) {
468+
return Arrays.binarySearch(RESERVED_JQL_WORDS, value.toLowerCase(Locale.ROOT)) > 0;
469+
}
274470
}

src/test/java/org/apache/maven/plugins/changes/jira/JqlQueryBuilderTestCase.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,17 @@ public void testOrderByIsLastElement() throws UnsupportedEncodingException {
146146
assertEquals(expected, actual);
147147
}
148148

149+
public void testQuoteReservedWord() throws UnsupportedEncodingException {
150+
String expected =
151+
URLEncoder.encode("project = \"EXEC\" ORDER BY key ASC, assignee DESC, reporter ASC", ENCODING);
152+
153+
String actual = createBuilder()
154+
.sortColumnNames("key ASC,assignee DESC, reporter ASC")
155+
.project("EXEC")
156+
.build();
157+
assertEquals(expected, actual);
158+
}
159+
149160
private JqlQueryBuilder createBuilder() {
150161
return new JqlQueryBuilder(new SilentLog());
151162
}

0 commit comments

Comments
 (0)