Skip to content

Commit 5f74b03

Browse files
author
James Leigh
authored
Merge pull request #809 from jamesrdf/issues/#679-limit-paged
Fix #679: Don't inline limit and offset if query already has them
2 parents d5b884b + ecfdc18 commit 5f74b03

1 file changed

Lines changed: 28 additions & 97 deletions

File tree

  • core/http/workbench/src/main/java/org/eclipse/rdf4j/workbench/util

core/http/workbench/src/main/java/org/eclipse/rdf4j/workbench/util/PagedQuery.java

Lines changed: 28 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,11 @@ public class PagedQuery {
2525

2626
private static final Pattern LIMIT_OR_OFFSET = Pattern.compile("((limit)|(offset))\\s+\\d+", FLAGS);
2727

28-
private static final Pattern SPLITTER = Pattern.compile("\\s");
29-
30-
private static final Pattern OFFSET_PATTERN = Pattern.compile("\\boffset\\s+\\d+\\b", FLAGS);
31-
32-
private static final Pattern LIMIT_PATTERN = Pattern.compile("\\blimit\\s+\\d+\\b", FLAGS);
33-
3428
private static final Pattern SERQL_NAMESPACE = Pattern.compile("\\busing namespace\\b", FLAGS);
3529

3630
private final String modifiedQuery;
3731

38-
private final boolean hasLimitAndOffset;
32+
private final boolean inlineLimitAndOffset;
3933

4034
private int limitSubstitute, offsetSubstitute;
4135

@@ -68,49 +62,27 @@ public PagedQuery(final String query, final QueryLanguage language, final int re
6862

6963
String rval = query;
7064

65+
/*
66+
* the matcher on the pattern will have a group for "limit l#" as well as a group for l#, similarly
67+
* for "offset o#" and o#. If either exists, disable paging.
68+
*/
69+
final Matcher matcher = LIMIT_OR_OFFSET.matcher(query);
7170
// requestLimit <= 0 actually means don't limit display
72-
hasLimitAndOffset = requestLimit > 0;
73-
if (hasLimitAndOffset) {
74-
/*
75-
* the matcher on the pattern will have a group for "limit l#" as well as a group for l#,
76-
* similarly for "offset o#" and o#. If either doesn't exist, it can be appended at the end.
77-
*/
78-
int queryLimit = -1;
79-
int queryOffset = -1;
80-
final Matcher matcher = LIMIT_OR_OFFSET.matcher(query);
81-
while (matcher.find()) {
82-
final String clause = matcher.group().toLowerCase();
83-
final int value = Integer.parseInt(SPLITTER.split(clause)[1]);
84-
if (clause.startsWith("limit")) {
85-
if (query.indexOf('}', matcher.end()) < 0) {
86-
queryLimit = value;
87-
}
88-
}
89-
else {
90-
queryOffset = value;
91-
}
92-
}
93-
94-
final boolean queryLimitExists = (queryLimit >= 0);
95-
final boolean queryOffsetExists = (queryOffset >= 0);
96-
final int maxQueryCount = getMaxQueryResultCount(queryLimit, queryOffset, queryLimitExists,
97-
queryOffsetExists);
98-
// gracefully handle malicious value
99-
final int offset = (requestOffset < 0) ? 0 : requestOffset;
100-
final int maxRequestCount = requestLimit + offset;
101-
limitSubstitute = (maxRequestCount < maxQueryCount) ? requestLimit : queryLimit - offset;
102-
offsetSubstitute = queryOffsetExists ? queryOffset + offset : offset;
103-
rval = modifyLimit(language, rval, queryLimit, queryLimitExists, queryOffsetExists,
104-
limitSubstitute);
105-
rval = modifyOffset(language, offset, rval, queryOffsetExists);
71+
inlineLimitAndOffset = requestLimit > 0 && !matcher.find();
72+
// gracefully handle malicious value
73+
offsetSubstitute = (requestOffset < 0) ? 0 : requestOffset;
74+
limitSubstitute = requestLimit;
75+
if (inlineLimitAndOffset) {
76+
rval = modifyLimit(language, rval, limitSubstitute);
77+
rval = modifyOffset(language, offsetSubstitute, rval);
10678
LOGGER.debug("Modified Query: {}", rval);
10779
}
10880

10981
this.modifiedQuery = rval;
11082
}
11183

11284
public boolean isPaged() {
113-
return this.hasLimitAndOffset;
85+
return this.inlineLimitAndOffset;
11486
}
11587

11688
public int getLimit() {
@@ -126,42 +98,19 @@ public String toString() {
12698
return this.modifiedQuery;
12799
}
128100

129-
private static int getMaxQueryResultCount(final int queryLimit, final int queryOffset,
130-
final boolean queryLimitExists, final boolean queryOffsetExists)
131-
{
132-
final int maxQueryCount = queryLimitExists ? (queryLimit + (queryOffsetExists ? queryOffset : 0))
133-
: Integer.MAX_VALUE;
134-
return maxQueryCount;
135-
}
136-
137-
private String modifyOffset(final QueryLanguage language, final int offset, final String query,
138-
final boolean queryOffsetExists)
139-
{
101+
private String modifyOffset(final QueryLanguage language, final int offset, final String query) {
140102
String rval = query;
141-
if (queryOffsetExists) {
142-
if (offsetSubstitute != offset) {
143-
// do a clause replacement
144-
final Matcher offsetMatcher = OFFSET_PATTERN.matcher(rval);
145-
final StringBuffer buffer = new StringBuffer();
146-
offsetMatcher.find();
147-
offsetMatcher.appendReplacement(buffer, "offset " + offsetSubstitute);
148-
offsetMatcher.appendTail(buffer);
149-
rval = buffer.toString();
103+
final String newOffsetClause = "offset " + offset;
104+
if (QueryLanguage.SPARQL == language) {
105+
if (offset > 0) {
106+
rval = ensureNewlineAndAppend(rval, newOffsetClause);
150107
}
151108
}
152109
else {
153-
final String newOffsetClause = "offset " + offset;
154-
if (QueryLanguage.SPARQL == language) {
155-
if (offset > 0) {
156-
rval = ensureNewlineAndAppend(rval, newOffsetClause);
157-
}
158-
}
159-
else {
160-
/*
161-
* SeRQL, add the clause before before the namespace section
162-
*/
163-
rval = insertAtMatchOnOwnLine(SERQL_NAMESPACE, rval, newOffsetClause);
164-
}
110+
/*
111+
* SeRQL, add the clause before before the namespace section
112+
*/
113+
rval = insertAtMatchOnOwnLine(SERQL_NAMESPACE, rval, newOffsetClause);
165114
}
166115
return rval;
167116
}
@@ -176,8 +125,8 @@ private static String ensureNewlineAndAppend(final String original, final String
176125
return buffer.append(append).toString();
177126
}
178127

179-
private static String modifyLimit(final QueryLanguage language, final String query, final int queryLimit,
180-
final boolean queryLimitExists, final boolean queryOffsetExists, final int limitSubstitute)
128+
private static String modifyLimit(final QueryLanguage language, final String query,
129+
final int limitSubstitute)
181130
{
182131
String rval = query;
183132

@@ -187,29 +136,11 @@ private static String modifyLimit(final QueryLanguage language, final String que
187136
* and LIMIT must precede OFFSET. This code makes no attempt to correct if the user places them out of
188137
* order in the query.
189138
*/
190-
if (queryLimitExists) {
191-
if (limitSubstitute != queryLimit) {
192-
// do a clause replacement
193-
final Matcher limitMatcher = LIMIT_PATTERN.matcher(rval);
194-
final StringBuffer buffer = new StringBuffer();
195-
limitMatcher.find();
196-
limitMatcher.appendReplacement(buffer, "limit " + limitSubstitute);
197-
limitMatcher.appendTail(buffer);
198-
rval = buffer.toString();
199-
}
139+
if (QueryLanguage.SPARQL == language) {
140+
rval = ensureNewlineAndAppend(rval, "limit " + limitSubstitute);
200141
}
201142
else {
202-
final String newLimitClause = "limit " + limitSubstitute;
203-
if (QueryLanguage.SPARQL == language) {
204-
rval = ensureNewlineAndAppend(rval, newLimitClause);
205-
}
206-
else {
207-
/*
208-
* SeRQL, add the clause before any offset clause or the namespace section
209-
*/
210-
final Pattern pattern = queryOffsetExists ? OFFSET_PATTERN : SERQL_NAMESPACE;
211-
rval = insertAtMatchOnOwnLine(pattern, rval, newLimitClause);
212-
}
143+
rval = insertAtMatchOnOwnLine(SERQL_NAMESPACE, rval, "limit " + limitSubstitute);
213144
}
214145
return rval;
215146
}

0 commit comments

Comments
 (0)