Skip to content

Commit 4be1cf3

Browse files
committed
fix(clickhouse): support SELECT SAMPLE 0.1/OFFSET and CREATE TABLE SAMPLE BY
1 parent ecaa26d commit 4be1cf3

File tree

4 files changed

+91
-17
lines changed

4 files changed

+91
-17
lines changed

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,30 @@ 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, true,
28+
null);
29+
}
30+
31+
public SampleClause(String keyword, String method, Number percentageArgument,
32+
String percentageUnit,
33+
Number repeatArgument, Number seedArgument, boolean argumentInBrackets,
34+
Number offsetArgument) {
2435
this.keyword = SampleKeyword.from(keyword);
2536
this.method = method == null || method.length() == 0 ? null : SampleMethod.from(method);
2637
this.percentageArgument = percentageArgument;
2738
this.percentageUnit = percentageUnit;
39+
this.argumentInBrackets = argumentInBrackets;
40+
this.offsetArgument = offsetArgument;
2841
this.repeatArgument = repeatArgument;
2942
this.seedArgument = seedArgument;
3043
}
@@ -68,6 +81,24 @@ public SampleClause setPercentageUnit(String percentageUnit) {
6881
return this;
6982
}
7083

84+
public boolean isArgumentInBrackets() {
85+
return argumentInBrackets;
86+
}
87+
88+
public SampleClause setArgumentInBrackets(boolean argumentInBrackets) {
89+
this.argumentInBrackets = argumentInBrackets;
90+
return this;
91+
}
92+
93+
public Number getOffsetArgument() {
94+
return offsetArgument;
95+
}
96+
97+
public SampleClause setOffsetArgument(Number offsetArgument) {
98+
this.offsetArgument = offsetArgument;
99+
return this;
100+
}
101+
71102
public SampleClause setRepeatArgument(Number repeatArgument) {
72103
this.repeatArgument = repeatArgument;
73104
return this;
@@ -104,8 +135,19 @@ public StringBuilder appendTo(StringBuilder builder) {
104135
}
105136

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

111153
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,19 @@ public void testCreateTableClickHouseMaterializedColumn() throws JSQLParserExcep
230230
assertSqlCanBeParsedAndDeparsed(statement, true);
231231
}
232232

233+
@Test
234+
public void testCreateTableClickHouseSampleBy() throws JSQLParserException {
235+
String statement = "CREATE TABLE tmp.events (\n"
236+
+ " id UInt64,\n"
237+
+ " user_id UInt32,\n"
238+
+ " timestamp DateTime\n"
239+
+ ")\n"
240+
+ "ENGINE = MergeTree()\n"
241+
+ "ORDER BY id\n"
242+
+ "SAMPLE BY id";
243+
assertSqlCanBeParsedAndDeparsed(statement, true);
244+
}
245+
233246
@Test
234247
public void testCreateTableIfNotExists() throws JSQLParserException {
235248
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)