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
7 changes: 4 additions & 3 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {

/**
* Pratt arithmetic operator precedence loop.
* Handles: *, /, %, ^, DIV (prec=6) and +, -, ||, |, &, <<, >> (prec=5)
* Handles: ^, ** (prec=7), *, /, %, DIV (prec=6) and +, -, ||, |, &, <<, >> (prec=5)
* Called only in real-parse mode (not syntactic-LOOKAHEAD mode) so action
* blocks execute correctly. Safe now that no syntactic production LOOKAHEADs
* scan through arithmetic expressions.
Expand Down Expand Up @@ -759,8 +759,9 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
if (jsonAccess || op == OP_JSON_PATH_DELETE || op == OP_JSON_PATH_EXISTS
|| (op == OP_CONCAT && Dialect.POSTGRESQL.name()
.equals(getAsString(Feature.dialect)))) prec = 4;
else if (op == OP_SLASH || op == OP_CARET || op == K_DIV) prec = 6;
else if (op == OP_POWER) prec = 7;
else if (op == OP_SLASH || op == K_DIV) prec = 6;
// ^ binds tighter than * / %, both as PostgreSQL's power and as MySQL's XOR
else if (op == OP_CARET || op == OP_POWER) prec = 7;
else if (op == S_HASH_OPERATOR) prec = 5;
else if (op == OP_CONCAT || op == OP_PIPE
|| op == OP_LSHIFT || op == OP_RSHIFT) prec = 5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd;
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.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.Between;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
Expand Down Expand Up @@ -217,4 +221,35 @@ public void testValuePositionNotStaysOnOperand() throws JSQLParserException {
Addition add = Assertions.assertInstanceOf(Addition.class, addition);
Assertions.assertInstanceOf(NotExpression.class, add.getRightExpression());
}

@Test
public void testCaretBindsTighterThanMultiplication() throws JSQLParserException {
// PostgreSQL's power and MySQL's XOR both evaluate 2 * 3 ^ 2 as 2 * (3 ^ 2)
Multiplication multiplication = Assertions.assertInstanceOf(Multiplication.class,
CCJSqlParserUtil.parseExpression("2 * 3 ^ 2"));
Assertions.assertInstanceOf(LongValue.class, multiplication.getLeftExpression());
Assertions.assertInstanceOf(BitwiseXor.class, multiplication.getRightExpression());

Division division = Assertions.assertInstanceOf(Division.class,
CCJSqlParserUtil.parseExpression("10 / 2 ^ 2"));
Assertions.assertInstanceOf(BitwiseXor.class, division.getRightExpression());

Modulo modulo = Assertions.assertInstanceOf(Modulo.class,
CCJSqlParserUtil.parseExpression("18 % 4 ^ 2"));
Assertions.assertInstanceOf(BitwiseXor.class, modulo.getRightExpression());

multiplication = Assertions.assertInstanceOf(Multiplication.class,
CCJSqlParserUtil.parseExpression("2 ^ 3 * 2"));
Assertions.assertInstanceOf(BitwiseXor.class, multiplication.getLeftExpression());

TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT pi() * r ^ 2 FROM circles");
}

@Test
public void testCaretIsLeftAssociative() throws JSQLParserException {
BitwiseXor outer = Assertions.assertInstanceOf(BitwiseXor.class,
CCJSqlParserUtil.parseExpression("2 ^ 3 ^ 2"));
Assertions.assertInstanceOf(BitwiseXor.class, outer.getLeftExpression());
Assertions.assertInstanceOf(LongValue.class, outer.getRightExpression());
}
}
Loading