Skip to content

Commit

Permalink
fix: refactor JsonExpression, avoiding expensive semantic lookahead…
Browse files Browse the repository at this point in the history
… and improving performance
  • Loading branch information
manticore-projects committed Dec 23, 2023
1 parent 45f98f8 commit 56515ab
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 82 deletions.
57 changes: 47 additions & 10 deletions src/main/java/net/sf/jsqlparser/expression/JsonExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,31 @@
*/
package net.sf.jsqlparser.expression;

import net.sf.jsqlparser.parser.ASTNodeAccessImpl;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
import java.util.Map;

public class JsonExpression extends ASTNodeAccessImpl implements Expression {
private Expression expr;

private List<String> idents = new ArrayList<String>();
private List<String> operators = new ArrayList<String>();
private final List<Map.Entry<String, String>> idents = new ArrayList<>();

public JsonExpression() {

}

public JsonExpression(Expression expr) {
this.expr = expr;
}

public JsonExpression(Expression expr, List<Map.Entry<String, String>> idents) {
this.expr = expr;
this.idents.addAll(idents);
}

@Override
public void accept(ExpressionVisitor expressionVisitor) {
Expand All @@ -34,24 +49,46 @@ public void setExpression(Expression expr) {
}

public void addIdent(String ident, String operator) {
idents.add(ident);
operators.add(operator);
idents.add(new AbstractMap.SimpleEntry<>(ident, operator));
}

public List<String> getIdents() {
public void addAllIdents(Collection<Map.Entry<String, String>> idents) {
this.idents.addAll(idents);
}

public List<Map.Entry<String, String>> getIdentList() {
return idents;
}

public Map.Entry<String, String> getIdent(int index) {
return idents.get(index);
}

@Deprecated
public List<String> getIdents() {
ArrayList<String> l = new ArrayList<>();
for (Map.Entry<String, String> ident : idents) {
l.add(ident.getKey());
}

return l;
}

@Deprecated
public List<String> getOperators() {
return operators;
ArrayList<String> l = new ArrayList<>();
for (Map.Entry<String, String> ident : idents) {
l.add(ident.getValue());
}
return l;
}

@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append(expr.toString());
for (int i = 0; i < idents.size(); i++) {
b.append(operators.get(i)).append(idents.get(i));
for (Map.Entry<String, String> ident : idents) {
b.append(ident.getValue()).append(ident.getKey());
}
return b.toString();
}
Expand Down
128 changes: 58 additions & 70 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -3638,7 +3638,27 @@ Expression Between(Expression leftExpression) :
}
{
[<K_NOT> { result.setNot(true); }]
<K_BETWEEN> betweenExpressionStart=SimpleExpression() <K_AND> betweenExpressionEnd=SimpleExpression()
<K_BETWEEN>
(
LOOKAHEAD( 3 ) betweenExpressionStart = ParenthesedSelect()
|
LOOKAHEAD( SimpleFunction() ) betweenExpressionStart = SimpleFunction()
|
LOOKAHEAD( RegularCondition() ) betweenExpressionStart = RegularCondition()
|
betweenExpressionStart = SimpleExpression()
)

<K_AND>
(
LOOKAHEAD( 3 ) betweenExpressionEnd = ParenthesedSelect()
|
LOOKAHEAD( SimpleFunction() ) betweenExpressionEnd = SimpleFunction()
|
LOOKAHEAD( RegularCondition() ) betweenExpressionEnd = RegularCondition()
|
betweenExpressionEnd = SimpleExpression()
)

{
result.setLeftExpression(leftExpression);
Expand Down Expand Up @@ -3985,7 +4005,10 @@ Expression SimpleExpression():
user = UserVariable()
( operation = "=" | operation = ":=" )
]
retval=ConcatExpression()

(
retval=ConcatExpression()
)
)
{
if (user != null) {
Expand Down Expand Up @@ -4172,6 +4195,8 @@ Expression PrimaryExpression() #PrimaryExpression:
boolean exclamationMarkNot = false;
boolean dateExpressionAllowed = true;
ExpressionList list;

final List<Map.Entry<String, String>> jsonIdents = new ArrayList<Map.Entry<String, String>>();
}
{
[ <K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; } ]
Expand All @@ -4195,15 +4220,13 @@ Expression PrimaryExpression() #PrimaryExpression:

| retval=XMLSerializeExpr()

| LOOKAHEAD(JsonExpression(), {!interrupted}) retval=JsonExpression()

| LOOKAHEAD(JsonFunction(), {!interrupted}) retval = JsonFunction()
| LOOKAHEAD(3, { !interrupted}) retval = JsonFunction()

| LOOKAHEAD(JsonAggregateFunction(), {!interrupted}) retval = JsonAggregateFunction()
| LOOKAHEAD(3, { !interrupted}) retval = JsonAggregateFunction()

| LOOKAHEAD(FullTextSearch(), {!interrupted}) retval = FullTextSearch()
| LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch()

| LOOKAHEAD(Function(), {!interrupted}) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ]
| LOOKAHEAD(Function(), { !interrupted}) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ]

| LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; }

Expand Down Expand Up @@ -4267,12 +4290,28 @@ Expression PrimaryExpression() #PrimaryExpression:
[ retval = ArrayExpression(retval) ]

( "::" type=ColDataType() {
castExpr = new CastExpression();
castExpr.setUseCastKeyword(false);
castExpr.setLeftExpression(retval);
castExpr.setColDataType(type);
retval=castExpr;
} )*
castExpr = new CastExpression();
castExpr.setUseCastKeyword(false);
castExpr.setLeftExpression(retval);
castExpr.setColDataType(type);
retval=castExpr;
}
)*

// Check for JSON operands
[
LOOKAHEAD(2) (
"->" (token=<S_CHAR_LITERAL> | token=<S_LONG>) { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"->")); }
|
"->>" (token=<S_CHAR_LITERAL> | token=<S_LONG>) { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"->>")); }
|
"#>" token=<S_CHAR_LITERAL> { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"#>")); }
|
"#>>" token=<S_CHAR_LITERAL> { jsonIdents.add(new AbstractMap.SimpleEntry<String, String>(token.image,"#>>")); }
)+
retval = JsonExpression(retval, jsonIdents)
]


( LOOKAHEAD(2) <K_AT> <K_DATETIMELITERAL> <K_ZONE> timezoneRightExpr=PrimaryExpression() {
if (timezoneExpr == null)
Expand Down Expand Up @@ -4428,65 +4467,13 @@ Expression ParenthesedExpression():
}
}

JsonExpression JsonExpression() : {
JsonExpression result = new JsonExpression();
Expression expr;
JsonExpression JsonExpression(Expression expr, List<Map.Entry<String, String>> idents) : {
JsonExpression result = new JsonExpression(expr, idents);
Token token;
ColDataType type = null;
CastExpression castExpr = null;
}
{
(
LOOKAHEAD(3, {!interrupted}) expr=CaseWhenExpression()
|
expr = SimpleJdbcParameter()
|
LOOKAHEAD(2, {!interrupted}) expr=JdbcNamedParameter()
|
expr=UserVariable()
|
LOOKAHEAD(JsonFunction(), {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expr = JsonFunction()
|
LOOKAHEAD(JsonAggregateFunction(), {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expr = JsonAggregateFunction()
|
LOOKAHEAD(FullTextSearch(), {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expr = FullTextSearch()
|
LOOKAHEAD( Function() , {getAsBoolean(Feature.allowComplexParsing) && !interrupted} ) expr=Function()
|
LOOKAHEAD( 2, {!interrupted} ) expr=Column()
|
token=<S_CHAR_LITERAL> { expr = new StringValue(token.image); }
|
LOOKAHEAD(ParenthesedExpression(), {getAsBoolean(Feature.allowComplexParsing)} ) expr = ParenthesedExpression()
|
LOOKAHEAD( 3, {getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expr=ParenthesedSelect()
)

(
"::" type=ColDataType()
{
castExpr = new CastExpression();
castExpr.setUseCastKeyword(false);
castExpr.setLeftExpression(expr);
castExpr.setColDataType(type);
expr=castExpr;
}
)*
{
result.setExpression(expr);
}

(
LOOKAHEAD(2) (
"->" (token=<S_CHAR_LITERAL> | token=<S_LONG>) {result.addIdent(token.image,"->");}
|
"->>" (token=<S_CHAR_LITERAL> | token=<S_LONG>) {result.addIdent(token.image,"->>");}
|
"#>" token=<S_CHAR_LITERAL> {result.addIdent(token.image,"#>");}
|
"#>>" token=<S_CHAR_LITERAL> {result.addIdent(token.image,"#>>");}
)
)+

// chaining JSON Expressions, e.g.
// '{"obj":{"field": "value"}}'::JSON -> 'obj'::TEXT ->> 'field'::TEXT
Expand All @@ -4504,8 +4491,7 @@ JsonExpression JsonExpression() : {
)
)+
{
result = new JsonExpression();
result.setExpression(expr);
result = new JsonExpression(expr);
}

(
Expand Down Expand Up @@ -5162,6 +5148,8 @@ Function SimpleFunction():
|
LOOKAHEAD( AllTableColumns() ) expr=AllTableColumns()
|
LOOKAHEAD( 3 ) expr = ParenthesedSelect()
|
LOOKAHEAD( SimpleFunction() ) expr = SimpleFunction()
|
LOOKAHEAD( RegularCondition() ) expr = RegularCondition()
Expand Down
Loading

0 comments on commit 56515ab

Please sign in to comment.