Skip to content

Commit e162024

Browse files
authored
Add support SELECT SAMPLE 0.1/OFFSET and CREATE TABLE SAMPLE BY (#2390)
* fix(clickhouse): support SELECT SAMPLE 0.1/OFFSET and CREATE TABLE SAMPLE BY * fix(clickhouse): support SELECT SAMPLE 0.1/OFFSET and CREATE TABLE SAMPLE BY
1 parent ecaa26d commit e162024

File tree

4 files changed

+107
-33
lines changed

4 files changed

+107
-33
lines changed

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

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,31 @@ public class SampleClause {
1414
private SampleMethod method;
1515
private Number percentageArgument;
1616
private String percentageUnit;
17+
private boolean argumentInBrackets = true;
18+
// ClickHouse specific
19+
private Number offsetArgument;
1720
private Number repeatArgument;
1821
// Oracle Specific
1922
private Number seedArgument;
2023

2124
public SampleClause(String keyword, String method, Number percentageArgument,
2225
String percentageUnit,
2326
Number repeatArgument, Number seedArgument) {
27+
this(keyword, method, percentageArgument, percentageUnit, repeatArgument, seedArgument,
28+
true,
29+
null);
30+
}
31+
32+
public SampleClause(String keyword, String method, Number percentageArgument,
33+
String percentageUnit,
34+
Number repeatArgument, Number seedArgument, boolean argumentInBrackets,
35+
Number offsetArgument) {
2436
this.keyword = SampleKeyword.from(keyword);
2537
this.method = method == null || method.length() == 0 ? null : SampleMethod.from(method);
2638
this.percentageArgument = percentageArgument;
2739
this.percentageUnit = percentageUnit;
40+
this.argumentInBrackets = argumentInBrackets;
41+
this.offsetArgument = offsetArgument;
2842
this.repeatArgument = repeatArgument;
2943
this.seedArgument = seedArgument;
3044
}
@@ -68,6 +82,24 @@ public SampleClause setPercentageUnit(String percentageUnit) {
6882
return this;
6983
}
7084

85+
public boolean isArgumentInBrackets() {
86+
return argumentInBrackets;
87+
}
88+
89+
public SampleClause setArgumentInBrackets(boolean argumentInBrackets) {
90+
this.argumentInBrackets = argumentInBrackets;
91+
return this;
92+
}
93+
94+
public Number getOffsetArgument() {
95+
return offsetArgument;
96+
}
97+
98+
public SampleClause setOffsetArgument(Number offsetArgument) {
99+
this.offsetArgument = offsetArgument;
100+
return this;
101+
}
102+
71103
public SampleClause setRepeatArgument(Number repeatArgument) {
72104
this.repeatArgument = repeatArgument;
73105
return this;
@@ -104,8 +136,19 @@ public StringBuilder appendTo(StringBuilder builder) {
104136
}
105137

106138
if (percentageArgument != null) {
107-
builder.append(" (").append(percentageArgument)
108-
.append(percentageUnit != null ? " " + percentageUnit : "").append(")");
139+
if (argumentInBrackets) {
140+
builder.append(" (").append(percentageArgument)
141+
.append(percentageUnit != null ? " " + percentageUnit : "").append(")");
142+
} else {
143+
builder.append(" ").append(percentageArgument);
144+
if (percentageUnit != null) {
145+
builder.append(" ").append(percentageUnit);
146+
}
147+
}
148+
}
149+
150+
if (offsetArgument != null) {
151+
builder.append(" OFFSET ").append(offsetArgument);
109152
}
110153

111154
if (repeatArgument != null) {

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

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3431,6 +3431,8 @@ SampleClause SampleClause():
34313431
String method=null;
34323432
Number percentageArgument;
34333433
String percentageUnit = null;
3434+
boolean argumentInBrackets = true;
3435+
Number offsetArgument = null;
34343436
Number repeatArgument=null;
34353437
Number seedArgument=null;
34363438
}
@@ -3455,22 +3457,30 @@ SampleClause SampleClause():
34553457
)
34563458
)
34573459

3458-
"(" percentageArgument = Number()
3459-
[
3460-
"%" { percentageUnit="%"; }
3461-
|
3462-
<K_PERCENT> { percentageUnit="PERCENT"; }
3463-
|
3464-
<K_ROWS> { percentageUnit="ROWS"; }
3465-
]
3466-
")"
3460+
(
3461+
"(" percentageArgument = Number()
3462+
[
3463+
"%" { percentageUnit="%"; }
3464+
|
3465+
<K_PERCENT> { percentageUnit="PERCENT"; }
3466+
|
3467+
<K_ROWS> { percentageUnit="ROWS"; }
3468+
]
3469+
")"
34673470

3468-
[ LOOKAHEAD(2) <K_REPEATABLE> "(" repeatArgument = Number() ")" ]
3471+
[ LOOKAHEAD(2) <K_REPEATABLE> "(" repeatArgument = Number() ")" ]
34693472

3470-
[ LOOKAHEAD(2) <K_SEED> "(" seedArgument = Number() ")" ]
3473+
[ LOOKAHEAD(2) <K_SEED> "(" seedArgument = Number() ")" ]
3474+
|
3475+
percentageArgument = Number() { argumentInBrackets = false; }
3476+
[ LOOKAHEAD(2) <K_OFFSET> offsetArgument = Number() ]
3477+
)
34713478

34723479
{
3473-
return new SampleClause(keyword, method, percentageArgument, percentageUnit, repeatArgument, seedArgument);
3480+
sampleClause = new SampleClause(keyword, method, percentageArgument, percentageUnit, repeatArgument, seedArgument);
3481+
sampleClause.setArgumentInBrackets(argumentInBrackets);
3482+
sampleClause.setOffsetArgument(offsetArgument);
3483+
return sampleClause;
34743484
}
34753485
}
34763486

@@ -9554,7 +9564,7 @@ List<String> CreateParameter():
95549564
| tk=<K_TYPE> | tk=<K_COMMENT> | tk=<K_USING> | tk=<K_COLLATE> | tk=<K_ASC>
95559565
| tk=<K_DESC> | tk=<K_TRUE> | tk=<K_FALSE> | tk=<K_PARALLEL> | tk=<K_BINARY> | tk=<K_START> | tk=<K_ORDER>
95569566
| tk=<K_TIME_KEY_EXPR> | tk=<K_RAW> | tk=<K_HASH> | tk=<K_FIRST> | tk=<K_LAST> | tk = <K_SIGNED> | tk = <K_UNSIGNED>
9557-
| tk=<K_ENGINE> | tk=<K_IDENTITY> | tk=<K_MATERIALIZED>
9567+
| tk=<K_ENGINE> | tk=<K_IDENTITY> | tk=<K_MATERIALIZED> | tk=<K_SAMPLE>
95589568
| tk="="
95599569
)
95609570
{ param.add(tk.image); }

src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@
99
*/
1010
package net.sf.jsqlparser.statement.create;
1111

12+
import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
13+
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
import static org.junit.jupiter.api.Assertions.assertFalse;
16+
import static org.junit.jupiter.api.Assertions.assertNotNull;
17+
import static org.junit.jupiter.api.Assertions.assertTrue;
18+
19+
import java.io.BufferedReader;
20+
import java.io.InputStreamReader;
21+
import java.io.StringReader;
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.Iterator;
25+
import java.util.List;
26+
import java.util.StringTokenizer;
1227
import net.sf.jsqlparser.JSQLParserException;
1328
import net.sf.jsqlparser.expression.LongValue;
1429
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
@@ -26,22 +41,6 @@
2641
import org.assertj.core.api.Assertions;
2742
import org.junit.jupiter.api.Test;
2843

29-
import java.io.BufferedReader;
30-
import java.io.InputStreamReader;
31-
import java.io.StringReader;
32-
import java.util.ArrayList;
33-
import java.util.Arrays;
34-
import java.util.Iterator;
35-
import java.util.List;
36-
import java.util.StringTokenizer;
37-
38-
import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
39-
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
40-
import static org.junit.jupiter.api.Assertions.assertEquals;
41-
import static org.junit.jupiter.api.Assertions.assertFalse;
42-
import static org.junit.jupiter.api.Assertions.assertNotNull;
43-
import static org.junit.jupiter.api.Assertions.assertTrue;
44-
4544
public class CreateTableTest {
4645

4746
private final CCJSqlParserManager parserManager = new CCJSqlParserManager();
@@ -230,6 +229,19 @@ public void testCreateTableClickHouseMaterializedColumn() throws JSQLParserExcep
230229
assertSqlCanBeParsedAndDeparsed(statement, true);
231230
}
232231

232+
@Test
233+
public void testCreateTableClickHouseSampleBy() throws JSQLParserException {
234+
String statement = "CREATE TABLE tmp.events (\n"
235+
+ " id UInt64,\n"
236+
+ " user_id UInt32,\n"
237+
+ " timestamp DateTime\n"
238+
+ ")\n"
239+
+ "ENGINE = MergeTree()\n"
240+
+ "ORDER BY id\n"
241+
+ "SAMPLE BY id";
242+
assertSqlCanBeParsedAndDeparsed(statement, true);
243+
}
244+
233245
@Test
234246
public void testCreateTableIfNotExists() throws JSQLParserException {
235247
assertSqlCanBeParsedAndDeparsed("CREATE TABLE IF NOT EXISTS animals (id INT NOT NULL)");

src/test/java/net/sf/jsqlparser/statement/select/SampleClauseTest.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,17 @@ void standardTestIssue1593(String sqlStr) throws JSQLParserException {
3838
"SELECT * from table_name SAMPLE BLOCK (99) SEED (10) ",
3939
"SELECT * from table_name SAMPLE BLOCK (99.1) SEED (10.1)"
4040
})
41-
void standardOracleIssue1826() throws JSQLParserException {
42-
String sqlStr = "SELECT * from table_name SAMPLE(99)";
41+
void standardOracleIssue1826(String sqlStr) throws JSQLParserException {
42+
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
43+
}
44+
45+
@ParameterizedTest
46+
@ValueSource(strings = {
47+
"SELECT * FROM events SAMPLE 0.1",
48+
"SELECT * FROM events SAMPLE 10000",
49+
"SELECT * FROM events SAMPLE 0.1 OFFSET 1000"
50+
})
51+
void clickHouseSampleClause(String sqlStr) throws JSQLParserException {
4352
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
4453
}
4554

0 commit comments

Comments
 (0)