Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Exponentiation;
import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
Expand Down Expand Up @@ -111,7 +112,7 @@
}

default <S> T visitLimit(Limit limit, S context) {
if (limit != null && !limit.isLimitNull() && !limit.isLimitAll()) {

Check warning on line 115 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java

View workflow job for this annotation

GitHub Actions / Maven Verify (macos-latest)

[deprecation] isLimitAll() in Limit has been deprecated

Check warning on line 115 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java

View workflow job for this annotation

GitHub Actions / Maven Verify (macos-latest)

[deprecation] isLimitNull() in Limit has been deprecated

Check warning on line 115 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java

View workflow job for this annotation

GitHub Actions / Maven Verify (windows-latest)

[deprecation] isLimitAll() in Limit has been deprecated

Check warning on line 115 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java

View workflow job for this annotation

GitHub Actions / Maven Verify (windows-latest)

[deprecation] isLimitNull() in Limit has been deprecated

Check warning on line 115 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java

View workflow job for this annotation

GitHub Actions / Maven Verify (ubuntu-latest)

[deprecation] isLimitAll() in Limit has been deprecated

Check warning on line 115 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java

View workflow job for this annotation

GitHub Actions / Maven Verify (ubuntu-latest)

[deprecation] isLimitNull() in Limit has been deprecated
if (limit.getOffset() != null) {
limit.getOffset().accept(this, context);
}
Expand Down Expand Up @@ -271,6 +272,15 @@

<S> T visit(IntegerDivision integerDivision, S context);

default <S> T visit(Exponentiation exponentiation, S context) {
visitExpression(exponentiation.getLeftExpression(), context);
return visitExpression(exponentiation.getRightExpression(), context);
}

default void visit(Exponentiation exponentiation) {
this.visit(exponentiation, null);
}

default void visit(IntegerDivision integerDivision) {
this.visit(integerDivision, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Exponentiation;
import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
Expand Down Expand Up @@ -198,6 +199,11 @@
return visitBinaryExpression(integerDivision, context);
}

@Override
public <S> T visit(Exponentiation exponentiation, S context) {
return visitBinaryExpression(exponentiation, context);
}

@Override
public <S> T visit(Multiplication multiplication, S context) {
return visitBinaryExpression(multiplication, context);
Expand Down Expand Up @@ -552,7 +558,7 @@
public <S> T visit(JsonExpression jsonExpr, S context) {
ArrayList<Expression> subExpressions = new ArrayList<>();
subExpressions.add(jsonExpr.getExpression());
subExpressions.addAll(jsonExpr.getIdents());

Check warning on line 561 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

View workflow job for this annotation

GitHub Actions / Maven Verify (macos-latest)

[deprecation] getIdents() in JsonExpression has been deprecated

Check warning on line 561 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

View workflow job for this annotation

GitHub Actions / Maven Verify (windows-latest)

[deprecation] getIdents() in JsonExpression has been deprecated

Check warning on line 561 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

View workflow job for this annotation

GitHub Actions / Maven Verify (ubuntu-latest)

[deprecation] getIdents() in JsonExpression has been deprecated
return visitExpressions(jsonExpr, context, subExpressions);
}

Expand Down Expand Up @@ -814,7 +820,7 @@

@Override
public <S> T visit(ConnectByRootOperator connectByRootOperator, S context) {
return connectByRootOperator.getColumn().accept(this, context);

Check warning on line 823 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

View workflow job for this annotation

GitHub Actions / Maven Verify (macos-latest)

[deprecation] getColumn() in ConnectByRootOperator has been deprecated

Check warning on line 823 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

View workflow job for this annotation

GitHub Actions / Maven Verify (windows-latest)

[deprecation] getColumn() in ConnectByRootOperator has been deprecated

Check warning on line 823 in src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

View workflow job for this annotation

GitHub Actions / Maven Verify (ubuntu-latest)

[deprecation] getColumn() in ConnectByRootOperator has been deprecated
}

@Override
Expand Down
18 changes: 17 additions & 1 deletion src/main/java/net/sf/jsqlparser/expression/SignedExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,23 @@ public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {

@Override
public String toString() {
return getSign() + expression.toString();
String operand = expression.toString();
return getSign() + (needsSpaceBefore(operand) ? " " : "") + operand;
}

/**
* Whether the sign must be separated from an operand starting with {@code firstChar}: "- -1"
* must not become the line comment "--1", nor "~ -a" or "~ ~a" a single operator such as "~-"
* or the LIKE operator "~~", as DuckDB and PostgreSQL read a run of signs containing {@code ~}.
*/
public boolean needsSpaceBefore(char firstChar) {
boolean signedOperand = firstChar == '+' || firstChar == '-' || firstChar == '~';
return sign == '-' && firstChar == '-' || sign == '~' && signedOperand
|| firstChar == '~' && (sign == '+' || sign == '-');
}

private boolean needsSpaceBefore(String operand) {
return !operand.isEmpty() && needsSpaceBefore(operand.charAt(0));
}

public SignedExpression withSign(char sign) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2026 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.expression.operators.arithmetic;

import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;

/** DuckDB's {@code a ** b}, {@code a} raised to the power {@code b}. */
public class Exponentiation extends BinaryExpression {

public Exponentiation() {}

public Exponentiation(Expression leftExpression, Expression rightExpression) {
super(leftExpression, rightExpression);
}

@Override
public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
return expressionVisitor.visit(this, context);
}

@Override
public String getStringExpression() {
return "**";
}

@Override
public Exponentiation withLeftExpression(Expression arg0) {
return (Exponentiation) super.withLeftExpression(arg0);
}

@Override
public Exponentiation withRightExpression(Expression arg0) {
return (Exponentiation) super.withRightExpression(arg0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public EqualsTo() {
super("=");
}

/** {@code operator} is {@code =} or DuckDB's {@code ==}. */
public EqualsTo(String operator) {
super(operator);
}

public EqualsTo(Expression left, Expression right) {
this();
setLeftExpression(left);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class LikeExpression extends BinaryExpression implements SupportsOldOracl
private boolean not = false;
private boolean useBinary = false;
private Expression escapeExpression = null;
private boolean useOperator = false;
private KeyWord likeKeyWord = KeyWord.LIKE;

public boolean isNot() {
Expand Down Expand Up @@ -48,12 +49,64 @@ public String getStringExpression() {
return likeKeyWord.toString();
}

/**
* The operator spelling of this condition when it was written as one and has one, e.g.
* {@code !~~} for {@code NOT LIKE}; otherwise {@code null} and the keyword form is used.
*/
public String getLikeOperator() {
if (!useOperator) {
return null;
}
switch (likeKeyWord) {
case LIKE:
return not ? "!~~" : "~~";
case ILIKE:
return not ? "!~~*" : "~~*";
case GLOB:
return not ? null : "~~~";
default:
return null;
}
}

/**
* Sets the keyword and {@code NOT} from DuckDB's and PostgreSQL's operator spelling: {@code ~~}
* is {@code LIKE}, {@code ~~*} {@code ILIKE}, {@code ~~~} {@code GLOB}, and a leading {@code !}
* negates the first two. The operator is printed while it matches the keyword and {@code NOT}.
*/
public LikeExpression setLikeOperator(String likeOperator) {
if (likeOperator == null) {
throw new IllegalArgumentException("The LIKE operator must not be null");
}
switch (likeOperator) {
case "~~":
case "!~~":
likeKeyWord = KeyWord.LIKE;
break;
case "~~*":
case "!~~*":
likeKeyWord = KeyWord.ILIKE;
break;
case "~~~":
likeKeyWord = KeyWord.GLOB;
break;
default:
throw new IllegalArgumentException("Unknown LIKE operator: " + likeOperator);
}
this.not = likeOperator.startsWith("!");
this.useOperator = true;
return this;
}

@Override
public String toString() {
String likeOperator = getLikeOperator();
String retval = (oraclePriorPosition == ORACLE_PRIOR_START ? "PRIOR " : "")
+ getLeftExpression() + " " + (not ? "NOT " : "")
+ (likeKeyWord == KeyWord.SIMILAR_TO ? "SIMILAR TO" : likeKeyWord) + " "
+ (useBinary ? "BINARY " : "") + getRightExpression();
+ getLeftExpression() + " "
+ (likeOperator != null ? likeOperator
: (not ? "NOT " : "")
+ (likeKeyWord == KeyWord.SIMILAR_TO ? "SIMILAR TO" : likeKeyWord))
+ " " + (useBinary ? "BINARY " : "") + getRightExpression();
if (escapeExpression != null) {
retval += " ESCAPE " + escapeExpression;
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Exponentiation;
import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
Expand Down Expand Up @@ -663,6 +664,12 @@ public <S> Void visit(IntegerDivision division, S context) {
return null;
}

@Override
public <S> Void visit(Exponentiation exponentiation, S context) {
visitBinaryExpression(exponentiation);
return null;
}

@Override
public <S> Void visit(DoubleValue doubleValue, S context) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Exponentiation;
import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
Expand Down Expand Up @@ -225,7 +226,7 @@ public <S> StringBuilder visit(OverlapsCondition overlapsCondition, S context) {

@Override
public <S> StringBuilder visit(EqualsTo equalsTo, S context) {
deparse(equalsTo, " = ", context);
deparse(equalsTo, " " + equalsTo.getStringExpression() + " ", context);
return builder;
}

Expand All @@ -241,6 +242,12 @@ public <S> StringBuilder visit(IntegerDivision division, S context) {
return builder;
}

@Override
public <S> StringBuilder visit(Exponentiation exponentiation, S context) {
deparse(exponentiation, " ** ", context);
return builder;
}

@Override
public <S> StringBuilder visit(DoubleValue doubleValue, S context) {
builder.append(doubleValue.toString());
Expand Down Expand Up @@ -425,7 +432,12 @@ public <S> StringBuilder visit(FullTextSearch fullTextSearch, S context) {
@Override
public <S> StringBuilder visit(SignedExpression signedExpression, S context) {
builder.append(signedExpression.getSign());
int operandStart = builder.length();
signedExpression.getExpression().accept(this, context);
if (builder.length() > operandStart
&& signedExpression.needsSpaceBefore(builder.charAt(operandStart))) {
builder.insert(operandStart, ' ');
}
return builder;
}

Expand Down Expand Up @@ -519,10 +531,14 @@ public <S> StringBuilder visit(LikeExpression likeExpression, S context) {
}
likeExpression.getLeftExpression().accept(this, context);
builder.append(" ");
if (likeExpression.isNot()) {
builder.append("NOT ");
if (likeExpression.getLikeOperator() != null) {
builder.append(likeExpression.getLikeOperator()).append(" ");
} else {
if (likeExpression.isNot()) {
builder.append("NOT ");
}
builder.append(keywordStr).append(" ");
}
builder.append(keywordStr).append(" ");
if (likeExpression.isUseBinary()) {
builder.append("BINARY ");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Exponentiation;
import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
Expand Down Expand Up @@ -199,6 +200,12 @@ public <S> Void visit(IntegerDivision division, S context) {
return null;
}

@Override
public <S> Void visit(Exponentiation exponentiation, S context) {
visitBinaryExpression(exponentiation, " ** ");
return null;
}

@Override
public <S> Void visit(DoubleValue doubleValue, S context) {
// nothing to validate
Expand Down
Loading
Loading