Skip to content

Commit 593e441

Browse files
committed
Merge pull request #155 from matthiasblaesing/informix_skip_first
Implement support for "SELECT SKIP <OFFSET> FIRST <LIMIT>..." co…
2 parents b3d76e7 + 4a33d8c commit 593e441

File tree

6 files changed

+302
-1
lines changed

6 files changed

+302
-1
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2015 JSQLParser
6+
* %%
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Lesser General Public License as
9+
* published by the Free Software Foundation, either version 2.1 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Lesser Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Lesser Public
18+
* License along with this program. If not, see
19+
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
20+
* #L%
21+
*/
22+
package net.sf.jsqlparser.statement.select;
23+
24+
import net.sf.jsqlparser.expression.JdbcParameter;
25+
26+
/**
27+
* A FIRST clause in the form [FIRST row_count] the alternative form
28+
* [LIMIT row_count] is also supported.
29+
*
30+
* Initial implementation was done for informix special syntax:
31+
* http://www-01.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_0156.htm
32+
*/
33+
public class First {
34+
public enum Keyword {
35+
FIRST,
36+
LIMIT
37+
}
38+
39+
private Keyword keyword;
40+
private Long rowCount;
41+
private JdbcParameter jdbcParameter;
42+
43+
public Long getRowCount() {
44+
return rowCount;
45+
}
46+
47+
public void setRowCount(Long rowCount) {
48+
this.rowCount = rowCount;
49+
}
50+
51+
public JdbcParameter getJdbcParameter() {
52+
return jdbcParameter;
53+
}
54+
55+
public void setJdbcParameter(JdbcParameter jdbcParameter) {
56+
this.jdbcParameter = jdbcParameter;
57+
}
58+
59+
public Keyword getKeyword() {
60+
return keyword;
61+
}
62+
63+
public void setKeyword(Keyword keyword) {
64+
this.keyword = keyword;
65+
}
66+
67+
@Override
68+
public String toString() {
69+
String result = keyword.name() + " ";
70+
71+
result += jdbcParameter != null ? jdbcParameter.toString() : rowCount;
72+
73+
return result;
74+
}
75+
}

src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public class PlainSelect implements SelectBody {
4747
private Limit limit;
4848
private Offset offset;
4949
private Fetch fetch;
50+
private Skip skip;
51+
private First first;
5052
private Top top;
5153
private OracleHierarchicalExpression oracleHierarchical = null;
5254
private boolean oracleSiblings = false;
@@ -170,6 +172,22 @@ public void setTop(Top top) {
170172
this.top = top;
171173
}
172174

175+
public Skip getSkip() {
176+
return skip;
177+
}
178+
179+
public void setSkip(Skip skip) {
180+
this.skip = skip;
181+
}
182+
183+
public First getFirst() {
184+
return first;
185+
}
186+
187+
public void setFirst(First first) {
188+
this.first = first;
189+
}
190+
173191
public Distinct getDistinct() {
174192
return distinct;
175193
}
@@ -246,6 +264,15 @@ public String toString() {
246264
sql.append("(");
247265
}
248266
sql.append("SELECT ");
267+
268+
if (skip != null) {
269+
sql.append(skip).append(" ");
270+
}
271+
272+
if (first != null) {
273+
sql.append(first).append(" ");
274+
}
275+
249276
if (distinct != null) {
250277
sql.append(distinct).append(" ");
251278
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2015 JSQLParser
6+
* %%
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Lesser General Public License as
9+
* published by the Free Software Foundation, either version 2.1 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Lesser Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Lesser Public
18+
* License along with this program. If not, see
19+
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
20+
* #L%
21+
*/
22+
package net.sf.jsqlparser.statement.select;
23+
24+
import net.sf.jsqlparser.expression.JdbcParameter;
25+
26+
/**
27+
* A skip clause in the form [SKIP row_count]
28+
*
29+
* Initial implementation was done for informix special syntax:
30+
* http://www-01.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_0156.htm
31+
*/
32+
public class Skip {
33+
34+
private Long rowCount;
35+
private JdbcParameter jdbcParameter;
36+
37+
public Long getRowCount() {
38+
return rowCount;
39+
}
40+
41+
public void setRowCount(Long rowCount) {
42+
this.rowCount = rowCount;
43+
}
44+
45+
public JdbcParameter getJdbcParameter() {
46+
return jdbcParameter;
47+
}
48+
49+
public void setJdbcParameter(JdbcParameter jdbcParameter) {
50+
this.jdbcParameter = jdbcParameter;
51+
}
52+
53+
@Override
54+
public String toString() {
55+
String result = "SKIP ";
56+
57+
result += jdbcParameter != null ? jdbcParameter.toString() : rowCount;
58+
59+
return result;
60+
}
61+
}

src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ public void visit(PlainSelect plainSelect) {
5656
buffer.append("(");
5757
}
5858
buffer.append("SELECT ");
59+
60+
Skip skip = plainSelect.getSkip();
61+
if (skip != null) {
62+
buffer.append(skip).append(" ");
63+
}
64+
65+
First first = plainSelect.getFirst();
66+
if (first != null) {
67+
buffer.append(first).append(" ");
68+
}
69+
5970
if (plainSelect.getDistinct() != null) {
6071
buffer.append("DISTINCT ");
6172
if (plainSelect.getDistinct().getOnSelectItems() != null) {

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
221221
| <K_KEEP:"KEEP">
222222
| <K_GROUP_CONCAT:"GROUP_CONCAT">
223223
| <K_SEPARATOR:"SEPARATOR">
224+
| <K_SKIP: "SKIP">
224225
}
225226

226227
TOKEN : /* Numeric Constants */
@@ -638,13 +639,19 @@ PlainSelect PlainSelect():
638639
Offset offset = null;
639640
Fetch fetch = null;
640641
Top top = null;
642+
Skip skip = null;
643+
First first = null;
641644
OracleHierarchicalExpression oracleHierarchicalQueryClause = null;
642645
List<Table> intoTables = null;
643646
Table updateTable = null;
644647
}
645648
{
646649
<K_SELECT>
647650

651+
[LOOKAHEAD(<K_SKIP> (<S_LONG> | "?")) skip = Skip() { plainSelect.setSkip(skip); } ]
652+
653+
[LOOKAHEAD((<K_FIRST> | <K_LIMIT>) (<S_LONG> | "?")) first = First() { plainSelect.setFirst(first); } ]
654+
648655
[
649656
<K_ALL>
650657
|
@@ -656,7 +663,6 @@ PlainSelect PlainSelect():
656663

657664
[top = Top() { plainSelect.setTop(top); } ]
658665

659-
660666
selectItems=SelectItemsList()
661667

662668
[intoTables = IntoClause() { plainSelect.setIntoTables(intoTables); } ]
@@ -1299,6 +1305,41 @@ Top Top():
12991305
}
13001306
}
13011307

1308+
// according to http://www-01.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_0156.htm
1309+
Skip Skip():
1310+
{
1311+
Skip skip = new Skip();
1312+
Token token = null;
1313+
}
1314+
{
1315+
<K_SKIP>
1316+
(
1317+
token=<S_LONG> { skip.setRowCount(Long.parseLong(token.image)); }
1318+
| "?" { skip.setJdbcParameter(new JdbcParameter()); } [ LOOKAHEAD(2) token = <S_LONG> { skip.getJdbcParameter().setIndex(Integer.valueOf(token.image)); } ]
1319+
)
1320+
{
1321+
return skip;
1322+
}
1323+
}
1324+
1325+
First First():
1326+
{
1327+
First first = new First();
1328+
Token token = null;
1329+
}
1330+
{
1331+
( <K_FIRST> { first.setKeyword(First.Keyword.FIRST); }
1332+
| <K_LIMIT> { first.setKeyword(First.Keyword.LIMIT); }
1333+
)
1334+
(
1335+
token=<S_LONG> { first.setRowCount(Long.parseLong(token.image)); }
1336+
| "?" { first.setJdbcParameter(new JdbcParameter()); } [ LOOKAHEAD(2) token = <S_LONG> { first.getJdbcParameter().setIndex(Integer.valueOf(token.image)); } ]
1337+
)
1338+
{
1339+
return first;
1340+
}
1341+
}
1342+
13021343
Expression Expression() #Expression :
13031344
{
13041345
Expression retval = null;

src/test/java/net/sf/jsqlparser/test/select/SelectTest.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,93 @@ public void testTopWithParenthesis() throws JSQLParserException {
425425

426426
assertStatementCanBeDeparsedAs(select, statement);
427427
}
428+
429+
public void testSkip() throws JSQLParserException {
430+
final String firstColumnName = "alias.columnName1";
431+
final String secondColumnName = "alias.columnName2";
432+
final String statement = "SELECT SKIP 5 " + firstColumnName + ", " + secondColumnName + " FROM schemaName.tableName alias ORDER BY " + secondColumnName + " DESC";
433+
final Select select = (Select) parserManager.parse(new StringReader(statement));
434+
435+
final PlainSelect selectBody = (PlainSelect) select.getSelectBody();
436+
437+
final Skip skip = selectBody.getSkip();
438+
assertEquals((long) 5, (long) skip.getRowCount());
439+
assertNull(skip.getJdbcParameter());
440+
441+
final List<SelectItem> selectItems = selectBody.getSelectItems();
442+
assertEquals(2, selectItems.size());
443+
assertEquals(firstColumnName, selectItems.get(0).toString());
444+
assertEquals(secondColumnName, selectItems.get(1).toString());
445+
446+
assertStatementCanBeDeparsedAs(select, statement);
447+
}
448+
449+
public void testFirst() throws JSQLParserException {
450+
final String firstColumnName = "alias.columnName1";
451+
final String secondColumnName = "alias.columnName2";
452+
final String statement = "SELECT FIRST 5 " + firstColumnName + ", " + secondColumnName + " FROM schemaName.tableName alias ORDER BY " + secondColumnName + " DESC";
453+
final Select select = (Select) parserManager.parse(new StringReader(statement));
454+
455+
final PlainSelect selectBody = (PlainSelect) select.getSelectBody();
456+
457+
final First limit = selectBody.getFirst();
458+
assertEquals((long) 5, (long) limit.getRowCount());
459+
assertNull(limit.getJdbcParameter());
460+
assertEquals(First.Keyword.FIRST, limit.getKeyword());
461+
462+
final List<SelectItem> selectItems = selectBody.getSelectItems();
463+
assertEquals(2, selectItems.size());
464+
assertEquals(firstColumnName, selectItems.get(0).toString());
465+
assertEquals(secondColumnName, selectItems.get(1).toString());
466+
467+
assertStatementCanBeDeparsedAs(select, statement);
468+
}
469+
470+
public void testFirstWithKeywordLimit() throws JSQLParserException {
471+
final String firstColumnName = "alias.columnName1";
472+
final String secondColumnName = "alias.columnName2";
473+
final String statement = "SELECT LIMIT ? " + firstColumnName + ", " + secondColumnName + " FROM schemaName.tableName alias ORDER BY " + secondColumnName + " DESC";
474+
final Select select = (Select) parserManager.parse(new StringReader(statement));
475+
476+
final PlainSelect selectBody = (PlainSelect) select.getSelectBody();
477+
478+
final First limit = selectBody.getFirst();
479+
assertNull(limit.getRowCount());
480+
assertNotNull(limit.getJdbcParameter());
481+
assertNull(limit.getJdbcParameter().getIndex());
482+
assertEquals(First.Keyword.LIMIT, limit.getKeyword());
483+
484+
final List<SelectItem> selectItems = selectBody.getSelectItems();
485+
assertEquals(2, selectItems.size());
486+
assertEquals(firstColumnName, selectItems.get(0).toString());
487+
assertEquals(secondColumnName, selectItems.get(1).toString());
428488

489+
assertStatementCanBeDeparsedAs(select, statement);
490+
}
491+
492+
public void testSkipFirst() throws JSQLParserException {
493+
final String statement = "SELECT SKIP ?1 FIRST ?2 c1, c2 FROM t1";
494+
final Select select = (Select) parserManager.parse(new StringReader(statement));
495+
496+
final PlainSelect selectBody = (PlainSelect) select.getSelectBody();
497+
498+
final Skip skip = selectBody.getSkip();
499+
assertNotNull(skip.getJdbcParameter());
500+
assertNotNull(skip.getJdbcParameter().getIndex());
501+
assertEquals((int) 1, (int) skip.getJdbcParameter().getIndex());
502+
final First first = selectBody.getFirst();
503+
assertNotNull(first.getJdbcParameter());
504+
assertNotNull(first.getJdbcParameter().getIndex());
505+
assertEquals((int) 2, (int) first.getJdbcParameter().getIndex());
506+
507+
final List<SelectItem> selectItems = selectBody.getSelectItems();
508+
assertEquals(2, selectItems.size());
509+
assertEquals("c1", selectItems.get(0).toString());
510+
assertEquals("c2", selectItems.get(1).toString());
511+
512+
assertStatementCanBeDeparsedAs(select, statement);
513+
}
514+
429515
public void testSelectItems() throws JSQLParserException {
430516
String statement = "SELECT myid AS MYID, mycol, tab.*, schema.tab.*, mytab.mycol2, myschema.mytab.mycol, myschema.mytab.* FROM mytable WHERE mytable.col = 9";
431517
Select select = (Select) parserManager.parse(new StringReader(statement));

0 commit comments

Comments
 (0)