Skip to content

Commit aee7cbc

Browse files
authored
Merge branch 'master' into feature/duckdb-syntax
2 parents c04286d + dec8f5d commit aee7cbc

103 files changed

Lines changed: 9834 additions & 57349 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codacy.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ engines:
44
exclude_paths:
55
# These fixtures use PostgreSQL grammar, not Transact-SQL.
66
- "src/test/resources/postgresql/**"
7+
# MATCH_RECOGNIZE fixtures use Oracle and BigQuery grammar.
8+
- "src/test/resources/net/sf/jsqlparser/statement/select/match-recognize/**"
9+
- "src/test/resources/net/sf/jsqlparser/statement/select/match-recognize-2350.sql"
710
exclude_paths:
811
- "site/**"

.gitignore

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
/src/site/sphinx/_themes
88

99
# Exclude the Auto-generated Changelog
10-
/src/site/sphinx/changelog.rst
11-
/src/site/sphinx/syntax_stable.rst
12-
/src/site/sphinx/syntax_snapshot.rst
13-
/src/site/sphinx/javadoc_stable.xml
14-
/src/site/sphinx/javadoc_snapshot.xml
10+
src/site/sphinx/changelog.rst
11+
src/site/sphinx/syntax_stable.rst
12+
src/site/sphinx/syntax_snapshot.rst
13+
src/site/sphinx/javadoc_stable.xml
14+
src/site/sphinx/javadoc_snapshot.xml
1515

1616
# Generated by javacc-maven-plugin
1717
/bin

CHANGELOG.md

Lines changed: 3484 additions & 2587 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ and missing syntax gets added on demand — [open an issue](https://github.com/J
140140
|---|---|
141141
| **Queries** | `SELECT` · `WITH …` · Piped SQL |
142142
| **ksqlDB windows** | JOIN `WITHIN`, window `GRACE PERIOD`, and `EMIT CHANGES`/`FINAL` |
143+
| **ClickHouse column selection** | `COLUMNS('regexp')` select items with chained `APPLY`, `EXCEPT`, and `REPLACE` transformers |
143144
| **DML** | `INSERT` · `UPDATE` · `UPSERT` · `MERGE` · `DELETE` · `TRUNCATE TABLE` |
144145
| **DDL** | `CREATE …` · `ALTER …` · `DROP …` |
145146
| **PostgreSQL RLS** | `CREATE POLICY` · `ALTER TABLE … ENABLE`/`DISABLE`/`FORCE`/`NO FORCE ROW LEVEL SECURITY` |
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.expression;
11+
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
15+
16+
/**
17+
* A ClickHouse {@code COLUMNS('regexp')} matcher with one or more transformers, for example
18+
* {@code COLUMNS('^metric_') APPLY(x -> round(x, 2))}.
19+
*
20+
* Without a transformer, {@code COLUMNS('regexp')} keeps parsing as a regular
21+
* {@link net.sf.jsqlparser.expression.Function}.
22+
*/
23+
public class ColumnsExpression extends ASTNodeAccessImpl implements Expression {
24+
25+
private Expression columns;
26+
private List<ColumnsTransformer> transformers;
27+
28+
public ColumnsExpression(Expression columns) {
29+
this.columns = columns;
30+
this.transformers = new ArrayList<>();
31+
}
32+
33+
public ColumnsExpression(Expression columns, List<ColumnsTransformer> transformers) {
34+
this.columns = columns;
35+
this.transformers = transformers;
36+
}
37+
38+
public Expression getColumns() {
39+
return columns;
40+
}
41+
42+
public ColumnsExpression setColumns(Expression columns) {
43+
this.columns = columns;
44+
return this;
45+
}
46+
47+
public List<ColumnsTransformer> getTransformers() {
48+
return transformers;
49+
}
50+
51+
public ColumnsExpression setTransformers(List<ColumnsTransformer> transformers) {
52+
this.transformers = transformers;
53+
return this;
54+
}
55+
56+
public List<Expression> getAllExpressions() {
57+
List<Expression> expressions = new ArrayList<>();
58+
if (columns != null) {
59+
expressions.add(columns);
60+
}
61+
for (ColumnsTransformer transformer : transformers) {
62+
transformer.collectExpressions(expressions);
63+
}
64+
return expressions;
65+
}
66+
67+
public StringBuilder appendTo(StringBuilder builder) {
68+
builder.append(columns);
69+
for (ColumnsTransformer transformer : transformers) {
70+
builder.append(" ").append(transformer);
71+
}
72+
return builder;
73+
}
74+
75+
@Override
76+
public String toString() {
77+
return appendTo(new StringBuilder()).toString();
78+
}
79+
80+
@Override
81+
public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
82+
return expressionVisitor.visit(this, context);
83+
}
84+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.expression;
11+
12+
import java.util.List;
13+
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
14+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
15+
import net.sf.jsqlparser.schema.Column;
16+
import net.sf.jsqlparser.statement.select.Select;
17+
import net.sf.jsqlparser.statement.select.SelectItem;
18+
19+
/**
20+
* A ClickHouse transformer following a {@code COLUMNS(...)} matcher, for example the
21+
* {@code APPLY(x -> round(x, 2))} in {@code SELECT COLUMNS('^m') APPLY(x -> round(x, 2))}.
22+
*
23+
* ClickHouse parses its transformers in a loop, so they may repeat and combine in any order.
24+
*/
25+
public class ColumnsTransformer extends ASTNodeAccessImpl {
26+
27+
public enum ColumnsTransformerType {
28+
APPLY, EXCEPT, REPLACE
29+
}
30+
31+
private ColumnsTransformerType type;
32+
private Expression applyExpression;
33+
private ParenthesedExpressionList<Column> exceptColumns;
34+
private List<SelectItem<?>> replaceItems;
35+
36+
public ColumnsTransformer(ColumnsTransformerType type) {
37+
this.type = type;
38+
}
39+
40+
public ColumnsTransformerType getType() {
41+
return type;
42+
}
43+
44+
public ColumnsTransformer setType(ColumnsTransformerType type) {
45+
this.type = type;
46+
return this;
47+
}
48+
49+
public Expression getApplyExpression() {
50+
return applyExpression;
51+
}
52+
53+
public ColumnsTransformer setApplyExpression(Expression applyExpression) {
54+
this.applyExpression = applyExpression;
55+
return this;
56+
}
57+
58+
public ParenthesedExpressionList<Column> getExceptColumns() {
59+
return exceptColumns;
60+
}
61+
62+
public ColumnsTransformer setExceptColumns(ParenthesedExpressionList<Column> exceptColumns) {
63+
this.exceptColumns = exceptColumns;
64+
return this;
65+
}
66+
67+
public List<SelectItem<?>> getReplaceItems() {
68+
return replaceItems;
69+
}
70+
71+
public ColumnsTransformer setReplaceItems(List<SelectItem<?>> replaceItems) {
72+
this.replaceItems = replaceItems;
73+
return this;
74+
}
75+
76+
void collectExpressions(List<Expression> expressions) {
77+
switch (type) {
78+
case APPLY:
79+
if (applyExpression != null) {
80+
expressions.add(applyExpression);
81+
}
82+
break;
83+
case EXCEPT:
84+
if (exceptColumns != null) {
85+
expressions.addAll(exceptColumns);
86+
}
87+
break;
88+
case REPLACE:
89+
if (replaceItems != null) {
90+
for (SelectItem<?> item : replaceItems) {
91+
expressions.add(item.getExpression());
92+
}
93+
}
94+
break;
95+
default:
96+
throw new IllegalStateException("Unhandled ColumnsTransformerType: " + type);
97+
}
98+
}
99+
100+
public StringBuilder appendTo(StringBuilder builder) {
101+
switch (type) {
102+
case APPLY:
103+
builder.append("APPLY(").append(applyExpression).append(")");
104+
break;
105+
case EXCEPT:
106+
builder.append("EXCEPT ").append(exceptColumns);
107+
break;
108+
case REPLACE:
109+
builder.append("REPLACE(").append(Select.getStringList(replaceItems)).append(")");
110+
break;
111+
default:
112+
throw new IllegalStateException("Unhandled ColumnsTransformerType: " + type);
113+
}
114+
return builder;
115+
}
116+
117+
@Override
118+
public String toString() {
119+
return appendTo(new StringBuilder()).toString();
120+
}
121+
}

src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,14 @@ default void visit(ExtractExpression extractExpression) {
510510
this.visit(extractExpression, null);
511511
}
512512

513+
default <S> T visit(RowPatternFunction function, S context) {
514+
return function.getFunction().accept(this, context);
515+
}
516+
517+
default void visit(RowPatternFunction function) {
518+
visit(function, null);
519+
}
520+
513521
<S> T visit(IntervalExpression intervalExpression, S context);
514522

515523
default void visit(IntervalExpression intervalExpression) {
@@ -805,6 +813,19 @@ default void visit(LambdaExpression lambdaExpression) {
805813
this.visit(lambdaExpression, null);
806814
}
807815

816+
default <S> T visit(ColumnsExpression columnsExpression, S context) {
817+
for (Expression expression : columnsExpression.getAllExpressions()) {
818+
if (expression != null) {
819+
expression.accept(this, context);
820+
}
821+
}
822+
return null;
823+
}
824+
825+
default void visit(ColumnsExpression columnsExpression) {
826+
this.visit(columnsExpression, null);
827+
}
828+
808829
<S> T visit(HighExpression highExpression, S context);
809830

810831
default void visit(HighExpression highExpression) {

src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,11 @@ public <S> T visit(LambdaExpression lambdaExpression, S context) {
875875
return lambdaExpression.getExpression().accept(this, context);
876876
}
877877

878+
@Override
879+
public <S> T visit(ColumnsExpression columnsExpression, S context) {
880+
return visitExpressions(columnsExpression, context, columnsExpression.getAllExpressions());
881+
}
882+
878883
@Override
879884
public <S> T visit(HighExpression highExpression, S context) {
880885
return highExpression.getExpression().accept(this, context);
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.expression;
11+
12+
import java.util.function.Consumer;
13+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
14+
15+
/** An explicit RUNNING or FINAL evaluation mode on a row-pattern function. */
16+
public class RowPatternFunction extends ASTNodeAccessImpl implements Expression {
17+
public enum EvaluationMode {
18+
RUNNING, FINAL
19+
}
20+
21+
private EvaluationMode evaluationMode;
22+
private Function function;
23+
24+
public RowPatternFunction(EvaluationMode evaluationMode, Function function) {
25+
this.evaluationMode = evaluationMode;
26+
this.function = function;
27+
}
28+
29+
public EvaluationMode getEvaluationMode() {
30+
return evaluationMode;
31+
}
32+
33+
public RowPatternFunction setEvaluationMode(EvaluationMode mode) {
34+
evaluationMode = mode;
35+
return this;
36+
}
37+
38+
public Function getFunction() {
39+
return function;
40+
}
41+
42+
public RowPatternFunction setFunction(Function function) {
43+
this.function = function;
44+
return this;
45+
}
46+
47+
@Override
48+
public <T, S> T accept(ExpressionVisitor<T> visitor, S context) {
49+
return visitor.visit(this, context);
50+
}
51+
52+
public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> expressions) {
53+
builder.append(evaluationMode).append(' ');
54+
expressions.accept(function);
55+
return builder;
56+
}
57+
58+
@Override
59+
public String toString() {
60+
StringBuilder builder = new StringBuilder();
61+
return appendTo(builder, expression -> builder.append(expression)).toString();
62+
}
63+
}

0 commit comments

Comments
 (0)