Skip to content

Commit 4ff498b

Browse files
Merge branch 'master' into fix/snowflake-json-path-keywords
2 parents 9fc1980 + cf057dd commit 4ff498b

102 files changed

Lines changed: 10242 additions & 370 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.

‎README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,17 @@ and missing syntax gets added on demand — [open an issue](https://github.com/J
151151
| **MySQL table maintenance** | `ANALYZE` · `CHECK` · `CHECKSUM` · `OPTIMIZE` · `REPAIR TABLE` |
152152
| **PostgreSQL maintenance** | `VACUUM` · `ANALYZE` · `CLUSTER` · `CHECKPOINT` |
153153
| **MySQL locks** | `LOCK TABLES` · `UNLOCK TABLES` · `LOCK INSTANCE FOR BACKUP` · `UNLOCK INSTANCE` |
154+
| **MySQL resource groups** | `CREATE`/`ALTER`/`DROP RESOURCE GROUP` · `SET RESOURCE GROUP` |
154155
| **PostgreSQL session statements** | `DISCARD` · `LISTEN` · `UNLISTEN` · `SHOW`/`RESET TIME ZONE`/`TRANSACTION ISOLATION LEVEL`/`SESSION AUTHORIZATION` · `COPY` options from before 9.0 |
156+
| **MySQL server administration** | `FLUSH` · `KILL` · `RESET PERSIST` · `HANDLER … OPEN`/`READ`/`CLOSE` |
155157
| **MySQL account management** | `CREATE`/`ALTER`/`RENAME USER` · `CREATE ROLE` · `SET ROLE` · `SET DEFAULT ROLE` · `SET PASSWORD` |
156158
| **Tablespaces** | MySQL and PostgreSQL `CREATE TABLESPACE` · `ALTER TABLESPACE` |
157159
| **PostgreSQL RLS** | `CREATE POLICY` · `ALTER TABLE … ENABLE`/`DISABLE`/`FORCE`/`NO FORCE ROW LEVEL SECURITY` |
158160
| **Routine changes** | `ALTER FUNCTION` · `ALTER PROCEDURE` · `ALTER ROUTINE` · PostgreSQL `ALTER TRIGGER` |
159161
| **MySQL metadata statements** | `SHOW [FULL] COLUMNS`/`FIELDS` · `SHOW TABLE STATUS` · `SHOW CREATE TABLE`/`VIEW`/`PROCEDURE`/`FUNCTION`/`TRIGGER`/`EVENT`/`DATABASE`/`USER` |
162+
| **MySQL utility statements** | `EXPLAIN`/`DESCRIBE [ANALYZE] FORMAT = …` · `EXPLAIN FOR CONNECTION` · `DESCRIBE t col` · `PREPARE … FROM` · `EXECUTE … USING` · `DROP PREPARE` · `DO` |
160163
| **PostgreSQL administration** | `CREATE`/`ALTER EVENT TRIGGER` · `REINDEX` · `SECURITY LABEL` |
164+
| **PostgreSQL types and rules** | `CREATE TYPE` (shell, composite, enum, range and base types) · `ALTER TYPE` · `CREATE RULE` · `ALTER RULE` |
161165
| **Informix constraints** | `ALTER TABLE … ADD CONSTRAINT` with trailing constraint names for primary, unique, foreign and check constraints; enable with `parser.withDialect(Dialect.INFORMIX)` |
162166
| **Salesforce SOQL** | `INCLUDES` · `EXCLUDES` |
163167

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import net.sf.jsqlparser.expression.operators.relational.Intersects;
4646
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
4747
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
48+
import net.sf.jsqlparser.expression.operators.relational.IsNormalizedExpression;
4849
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
4950
import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression;
5051
import net.sf.jsqlparser.expression.operators.relational.IsJsonExpression;
@@ -395,6 +396,14 @@ default void visit(IsUnknownExpression isUnknownExpression) {
395396
this.visit(isUnknownExpression, null);
396397
}
397398

399+
default <S> T visit(IsNormalizedExpression isNormalizedExpression, S context) {
400+
return isNormalizedExpression.getLeftExpression().accept(this, context);
401+
}
402+
403+
default void visit(IsNormalizedExpression isNormalizedExpression) {
404+
this.visit(isNormalizedExpression, null);
405+
}
406+
398407
<S> T visit(LikeExpression likeExpression, S context);
399408

400409
default void visit(LikeExpression likeExpression) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import net.sf.jsqlparser.expression.operators.relational.Intersects;
4949
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
5050
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
51+
import net.sf.jsqlparser.expression.operators.relational.IsNormalizedExpression;
5152
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
5253
import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression;
5354
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
@@ -296,6 +297,11 @@ public <S> T visit(IsUnknownExpression isUnknownExpression, S context) {
296297
return isUnknownExpression.getLeftExpression().accept(this, context);
297298
}
298299

300+
@Override
301+
public <S> T visit(IsNormalizedExpression isNormalizedExpression, S context) {
302+
return isNormalizedExpression.getLeftExpression().accept(this, context);
303+
}
304+
299305
@Override
300306
public <S> T visit(LikeExpression likeExpression, S context) {
301307
return visitExpressions(likeExpression, context, likeExpression.getLeftExpression(),

‎src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java‎

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414

1515
import java.util.Arrays;
1616
import java.util.List;
17+
import java.util.function.Consumer;
1718

1819
public class TimezoneExpression extends ASTNodeAccessImpl implements Expression {
1920

2021
private final ExpressionList<Expression> timezoneExpressions = new ExpressionList<>();
2122
private Expression leftExpression;
23+
private boolean atLocal;
2224

2325
public TimezoneExpression() {
2426
leftExpression = null;
@@ -51,13 +53,37 @@ public void addTimezoneExpression(Expression... timezoneExpr) {
5153
this.timezoneExpressions.addAll(Arrays.asList(timezoneExpr));
5254
}
5355

54-
@Override
55-
public String toString() {
56-
StringBuilder returnValue = new StringBuilder(leftExpression.toString());
56+
/**
57+
* Whether the expression ends with {@code AT LOCAL}, which converts to the session time zone.
58+
* It follows the {@code AT TIME ZONE} conversions of this expression, if there are any.
59+
*/
60+
public boolean isAtLocal() {
61+
return atLocal;
62+
}
63+
64+
public TimezoneExpression setAtLocal(boolean atLocal) {
65+
this.atLocal = atLocal;
66+
return this;
67+
}
68+
69+
/**
70+
* Appends the expression, rendering the operand and each time zone through the renderer.
71+
*/
72+
public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> expressionRenderer) {
73+
expressionRenderer.accept(leftExpression);
5774
for (Expression expr : timezoneExpressions) {
58-
returnValue.append(" AT TIME ZONE ").append(expr.toString());
75+
builder.append(" AT TIME ZONE ");
76+
expressionRenderer.accept(expr);
77+
}
78+
if (atLocal) {
79+
builder.append(" AT LOCAL");
5980
}
81+
return builder;
82+
}
6083

61-
return returnValue.toString();
84+
@Override
85+
public String toString() {
86+
StringBuilder builder = new StringBuilder();
87+
return appendTo(builder, builder::append).toString();
6288
}
6389
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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.operators.relational;
11+
12+
import java.util.function.Consumer;
13+
import net.sf.jsqlparser.expression.Expression;
14+
import net.sf.jsqlparser.expression.ExpressionVisitor;
15+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
16+
17+
/**
18+
* The Unicode normalization test {@code expression IS [NOT] [NFC | NFD | NFKC | NFKD] NORMALIZED}.
19+
*/
20+
public class IsNormalizedExpression extends ASTNodeAccessImpl implements Expression {
21+
/** The Unicode normalization forms. */
22+
public enum NormalForm {
23+
NFC, NFD, NFKC, NFKD;
24+
25+
/** Whether the word names a normalization form, in any case. */
26+
public static boolean isNormalForm(String word) {
27+
for (NormalForm form : values()) {
28+
if (form.name().equalsIgnoreCase(word)) {
29+
return true;
30+
}
31+
}
32+
return false;
33+
}
34+
}
35+
36+
private Expression leftExpression;
37+
private boolean not;
38+
private NormalForm normalForm;
39+
40+
public IsNormalizedExpression() {
41+
// empty constructor
42+
}
43+
44+
public IsNormalizedExpression(Expression leftExpression) {
45+
this.leftExpression = leftExpression;
46+
}
47+
48+
public Expression getLeftExpression() {
49+
return leftExpression;
50+
}
51+
52+
public void setLeftExpression(Expression leftExpression) {
53+
this.leftExpression = leftExpression;
54+
}
55+
56+
public IsNormalizedExpression withLeftExpression(Expression leftExpression) {
57+
this.setLeftExpression(leftExpression);
58+
return this;
59+
}
60+
61+
public <E extends Expression> E getLeftExpression(Class<E> type) {
62+
return type.cast(getLeftExpression());
63+
}
64+
65+
public boolean isNot() {
66+
return not;
67+
}
68+
69+
public void setNot(boolean not) {
70+
this.not = not;
71+
}
72+
73+
public IsNormalizedExpression withNot(boolean not) {
74+
this.setNot(not);
75+
return this;
76+
}
77+
78+
/** The normalization form as written, or null when it is omitted (the server tests NFC). */
79+
public NormalForm getNormalForm() {
80+
return normalForm;
81+
}
82+
83+
public void setNormalForm(NormalForm normalForm) {
84+
this.normalForm = normalForm;
85+
}
86+
87+
public IsNormalizedExpression withNormalForm(NormalForm normalForm) {
88+
this.setNormalForm(normalForm);
89+
return this;
90+
}
91+
92+
@Override
93+
public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
94+
return expressionVisitor.visit(this, context);
95+
}
96+
97+
/** Appends the test, rendering the operand through the renderer. */
98+
public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> expressionRenderer) {
99+
expressionRenderer.accept(leftExpression);
100+
builder.append(not ? " IS NOT " : " IS ");
101+
if (normalForm != null) {
102+
builder.append(normalForm).append(' ');
103+
}
104+
return builder.append("NORMALIZED");
105+
}
106+
107+
@Override
108+
public String toString() {
109+
StringBuilder builder = new StringBuilder();
110+
return appendTo(builder, builder::append).toString();
111+
}
112+
}

‎src/main/java/net/sf/jsqlparser/parser/RoutineBodyBoundary.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ private void acceptStatementToken(Token token, Token next) {
248248
if (statementStart) {
249249
statementKind = kind;
250250
}
251-
if (statementKind == K_DECLARE && keyword(token, "HANDLER")) {
251+
if (statementKind == K_DECLARE && token.kind == K_HANDLER) {
252252
handlerAction = true;
253253
}
254254
statementStart = false;

‎src/main/java/net/sf/jsqlparser/parser/feature/Feature.java‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import net.sf.jsqlparser.statement.TableMaintenanceStatement;
3333
import net.sf.jsqlparser.statement.UseStatement;
3434
import net.sf.jsqlparser.statement.XaStatement;
35+
import net.sf.jsqlparser.statement.admin.FlushStatement;
36+
import net.sf.jsqlparser.statement.admin.KillStatement;
3537
import net.sf.jsqlparser.statement.alter.Alter;
3638
import net.sf.jsqlparser.statement.alter.AlterEventTrigger;
3739
import net.sf.jsqlparser.statement.alter.sequence.AlterSequence;
@@ -55,11 +57,15 @@
5557
import net.sf.jsqlparser.statement.drop.Drop;
5658
import net.sf.jsqlparser.statement.execute.Execute;
5759
import net.sf.jsqlparser.statement.grant.Grant;
60+
import net.sf.jsqlparser.statement.handler.HandlerStatement;
5861
import net.sf.jsqlparser.statement.lock.BackupLockStatement;
5962
import net.sf.jsqlparser.statement.lock.UnlockStatement;
6063
import net.sf.jsqlparser.statement.merge.Merge;
6164
import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement;
6265
import net.sf.jsqlparser.statement.reindex.Reindex;
66+
import net.sf.jsqlparser.statement.resourcegroup.AlterResourceGroup;
67+
import net.sf.jsqlparser.statement.resourcegroup.CreateResourceGroup;
68+
import net.sf.jsqlparser.statement.resourcegroup.SetResourceGroup;
6369
import net.sf.jsqlparser.statement.role.ReassignOwned;
6470
import net.sf.jsqlparser.statement.select.Fetch;
6571
import net.sf.jsqlparser.statement.select.First;
@@ -494,6 +500,27 @@ public enum Feature {
494500
*/
495501
tableMaintenance,
496502

503+
/**
504+
* MySQL "FLUSH" statement is allowed
505+
*
506+
* @see FlushStatement
507+
*/
508+
flush,
509+
510+
/**
511+
* MySQL "KILL" statement is allowed
512+
*
513+
* @see KillStatement
514+
*/
515+
kill,
516+
517+
/**
518+
* MySQL "HANDLER ... OPEN", "HANDLER ... READ" and "HANDLER ... CLOSE" statements are allowed
519+
*
520+
* @see HandlerStatement
521+
*/
522+
handler,
523+
497524
/**
498525
* PostgreSQL "VACUUM" statement is allowed
499526
*
@@ -539,6 +566,11 @@ public enum Feature {
539566
*/
540567
executeStatementImmediate,
541568

569+
/**
570+
* MySQL "EXECUTE name USING @variable, ..." of a prepared statement is allowed
571+
*
572+
* @see Execute#getUsingVariables()
573+
*/
542574
executeUsing,
543575
/**
544576
* "PREPARE" and "DEALLOCATE" of a prepared statement are allowed
@@ -796,6 +828,24 @@ public enum Feature {
796828
* @see BackupLockStatement
797829
*/
798830
backupLock,
831+
/**
832+
* MySQL "CREATE RESOURCE GROUP" statement is allowed
833+
*
834+
* @see CreateResourceGroup
835+
*/
836+
createResourceGroup,
837+
/**
838+
* MySQL "ALTER RESOURCE GROUP" statement is allowed
839+
*
840+
* @see AlterResourceGroup
841+
*/
842+
alterResourceGroup,
843+
/**
844+
* MySQL "SET RESOURCE GROUP" statement is allowed
845+
*
846+
* @see SetResourceGroup
847+
*/
848+
setResourceGroup,
799849
/**
800850
* SQL "COMMENT ON" statement is allowed
801851
*
@@ -945,6 +995,12 @@ public enum Feature {
945995
* @see net.sf.jsqlparser.statement.alter.AlterTrigger
946996
*/
947997
alterTrigger,
998+
/**
999+
* PostgreSQL "ALTER RULE" statement is allowed
1000+
*
1001+
* @see net.sf.jsqlparser.statement.alter.AlterRule
1002+
*/
1003+
alterRule,
9481004
/**
9491005
* SQL block starting with "BEGIN" and ends with "END" statement is allowed
9501006
*
@@ -982,6 +1038,12 @@ public enum Feature {
9821038
* @see net.sf.jsqlparser.statement.notify.ListenStatement
9831039
*/
9841040
listen,
1041+
/**
1042+
* MySQL "RESET PERSIST" statement is allowed
1043+
*
1044+
* @see ResetStatement#isPersist()
1045+
*/
1046+
resetPersist,
9851047
/**
9861048
* @see Pivot
9871049
*/

‎src/main/java/net/sf/jsqlparser/schema/TableReference.java‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111

1212
import java.io.Serializable;
1313

14-
/** A relation target with optional PostgreSQL inheritance scope, shared by LOCK and TRUNCATE. */
14+
/**
15+
* A relation target with optional PostgreSQL inheritance scope, shared by LOCK, TRUNCATE and the
16+
* targets of UPDATE, DELETE and MERGE.
17+
*/
1518
public class TableReference implements Serializable {
1619
private Table table;
1720
private boolean only;
@@ -84,6 +87,27 @@ public StringBuilder appendTo(StringBuilder builder) {
8487
return builder;
8588
}
8689

90+
/**
91+
* Appends the target of UPDATE, DELETE or MERGE (PostgreSQL's relation_expr_opt_alias): the
92+
* inheritance scope surrounds the table name and the alias of the table follows it. A target
93+
* without a scope is the table as it renders itself, with its alias and hints.
94+
*/
95+
public StringBuilder appendWithAliasTo(StringBuilder builder) {
96+
if (!only && !includeDescendants || table == null) {
97+
return builder.append(table);
98+
}
99+
appendTo(builder);
100+
if (table.getAlias() != null) {
101+
builder.append(table.getAlias());
102+
}
103+
return builder;
104+
}
105+
106+
/** Whether ONLY or * describes the inheritance scope of the table. */
107+
public boolean hasInheritanceScope() {
108+
return only || includeDescendants;
109+
}
110+
87111
@Override
88112
public String toString() {
89113
return appendTo(new StringBuilder()).toString();

0 commit comments

Comments
 (0)