Polishing.
Reuse setReturningFunction and genericFunctionArguments structure for easier extension. Split fromRoot into separate parser function fragments. Fix trailing spaces. See: #3864 Original pull request: #3879
This commit is contained in:
@@ -112,15 +112,11 @@ joinSpecifier
|
||||
;
|
||||
|
||||
fromRoot
|
||||
: entityName variable?
|
||||
| LATERAL? '(' subquery ')' variable?
|
||||
| functionCallAsFromSource variable?
|
||||
: entityName variable? # RootEntity
|
||||
| LATERAL? '(' subquery ')' variable? # RootSubquery
|
||||
| setReturningFunction variable? # RootFunction
|
||||
;
|
||||
|
||||
functionCallAsFromSource
|
||||
: identifier '(' (expression (',' expression)*)? ')'
|
||||
;
|
||||
|
||||
join
|
||||
: joinType JOIN FETCH? joinTarget joinRestriction? // Spec BNF says joinType isn't optional, but text says that it is.
|
||||
;
|
||||
@@ -128,11 +124,7 @@ join
|
||||
joinTarget
|
||||
: path variable? # JoinPath
|
||||
| LATERAL? '(' subquery ')' variable? # JoinSubquery
|
||||
| functionCallAsJoinTarget variable? # JoinFunctionCall
|
||||
;
|
||||
|
||||
functionCallAsJoinTarget
|
||||
: identifier '(' (expression (',' expression)*)? ')'
|
||||
| setReturningFunction variable? # JoinFunctionCall
|
||||
;
|
||||
|
||||
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-update
|
||||
@@ -768,6 +760,14 @@ function
|
||||
| genericFunction # GenericFunctionInvocation
|
||||
;
|
||||
|
||||
setReturningFunction
|
||||
: simpleSetReturningFunction
|
||||
;
|
||||
|
||||
simpleSetReturningFunction
|
||||
: identifier '(' genericFunctionArguments? ')'
|
||||
;
|
||||
|
||||
/**
|
||||
* Any function with an irregular syntax for the argument list
|
||||
*
|
||||
@@ -1888,4 +1888,4 @@ ESCAPE_SEQUENCE
|
||||
|
||||
QUOTED_IDENTIFIER
|
||||
: BACKTICK ( ESCAPE_SEQUENCE | '\\' BACKTICK | ~([`]) )* BACKTICK
|
||||
;
|
||||
;
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.jspecify.annotations.Nullable;
|
||||
* Hibernate-specific query details capturing common table expression details.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author oscar.fanchin
|
||||
* @author Oscar Fanchin
|
||||
* @since 3.5
|
||||
*/
|
||||
class HibernateQueryInformation extends QueryInformation {
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.springframework.data.jpa.repository.query.QueryTransformers.CountSele
|
||||
* @author Greg Turnquist
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author oscar.fanchin
|
||||
* @author Oscar Fanchin
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@@ -113,7 +113,6 @@ class HqlCountQueryTransformer extends HqlQueryRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ctx.whereClause() != null) {
|
||||
builder.appendExpression(visit(ctx.whereClause()));
|
||||
}
|
||||
@@ -133,48 +132,6 @@ class HqlCountQueryTransformer extends HqlQueryRenderer {
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryRendererBuilder visitFromRoot(HqlParser.FromRootContext ctx) {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
if (ctx.entityName() != null) {
|
||||
|
||||
builder.appendExpression(visit(ctx.entityName()));
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
} else if (ctx.subquery() != null) {
|
||||
|
||||
if (ctx.LATERAL() != null) {
|
||||
builder.append(QueryTokens.expression(ctx.LATERAL()));
|
||||
}
|
||||
|
||||
QueryRendererBuilder nested = QueryRenderer.builder();
|
||||
|
||||
nested.append(TOKEN_OPEN_PAREN);
|
||||
nested.appendInline(visit(ctx.subquery()));
|
||||
nested.append(TOKEN_CLOSE_PAREN);
|
||||
|
||||
builder.appendExpression(nested);
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
} else if (ctx.functionCallAsFromSource() != null) {
|
||||
|
||||
builder.appendExpression(visit(ctx.functionCallAsFromSource()));
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryRendererBuilder visitJoin(HqlParser.JoinContext ctx) {
|
||||
|
||||
@@ -193,6 +150,7 @@ class HqlCountQueryTransformer extends HqlQueryRenderer {
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitSelectClause(HqlParser.SelectClauseContext ctx) {
|
||||
|
||||
|
||||
@@ -21,15 +21,15 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.HqlParser.VariableContext;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.HqlParser.VariableContext;
|
||||
|
||||
/**
|
||||
* {@link ParsedQueryIntrospector} for HQL queries.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author oscar.fanchin
|
||||
* @author Oscar Fanchin
|
||||
*/
|
||||
@SuppressWarnings({ "UnreachableCode", "ConstantValue" })
|
||||
class HqlQueryIntrospector extends HqlBaseVisitor<Void> implements ParsedQueryIntrospector<HibernateQueryInformation> {
|
||||
@@ -52,9 +52,9 @@ class HqlQueryIntrospector extends HqlBaseVisitor<Void> implements ParsedQueryIn
|
||||
@Override
|
||||
public Void visitSelectClause(HqlParser.SelectClauseContext ctx) {
|
||||
|
||||
if (!projectionProcessed) {
|
||||
projection = captureSelectItems(ctx.selectionList().selection(), renderer);
|
||||
projectionProcessed = true;
|
||||
if (!this.projectionProcessed) {
|
||||
this.projection = captureSelectItems(ctx.selectionList().selection(), renderer);
|
||||
this.projectionProcessed = true;
|
||||
}
|
||||
|
||||
return super.visitSelectClause(ctx);
|
||||
@@ -65,21 +65,36 @@ class HqlQueryIntrospector extends HqlBaseVisitor<Void> implements ParsedQueryIn
|
||||
this.hasCte = true;
|
||||
return super.visitCte(ctx);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Void visitFunctionCallAsFromSource(HqlParser.FunctionCallAsFromSourceContext ctx) {
|
||||
this.hasFromFunction = true;
|
||||
return super.visitFunctionCallAsFromSource(ctx);
|
||||
public Void visitRootEntity(HqlParser.RootEntityContext ctx) {
|
||||
|
||||
if (this.primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
|
||||
this.primaryFromAlias = capturePrimaryAlias(ctx.variable());
|
||||
}
|
||||
|
||||
return super.visitRootEntity(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitFromRoot(HqlParser.FromRootContext ctx) {
|
||||
public Void visitRootSubquery(HqlParser.RootSubqueryContext ctx) {
|
||||
|
||||
if (primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
|
||||
primaryFromAlias = capturePrimaryAlias(ctx.variable());
|
||||
if (this.primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
|
||||
this.primaryFromAlias = capturePrimaryAlias(ctx.variable());
|
||||
}
|
||||
|
||||
return super.visitFromRoot(ctx);
|
||||
return super.visitRootSubquery(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitRootFunction(HqlParser.RootFunctionContext ctx) {
|
||||
|
||||
if (this.primaryFromAlias == null && ctx.variable() != null && !HqlQueryRenderer.isSubquery(ctx)) {
|
||||
this.primaryFromAlias = capturePrimaryAlias(ctx.variable());
|
||||
this.hasFromFunction = true;
|
||||
}
|
||||
|
||||
return super.visitRootFunction(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -64,24 +64,6 @@ class HqlQueryRenderer extends HqlBaseVisitor<QueryTokenStream> {
|
||||
return visit(ctx.ql_statement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitFunctionCallAsFromSource(HqlParser.FunctionCallAsFromSourceContext ctx) {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
builder.append(visit(ctx.identifier()));
|
||||
|
||||
builder.append(TOKEN_OPEN_PAREN);
|
||||
|
||||
if (!ctx.expression().isEmpty()) {
|
||||
builder.append(QueryTokenStream.concatExpressions(ctx.expression(), this::visit, TOKEN_COMMA));
|
||||
}
|
||||
|
||||
builder.append(TOKEN_CLOSE_PAREN);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitQl_statement(HqlParser.Ql_statementContext ctx) {
|
||||
|
||||
@@ -369,48 +351,78 @@ class HqlQueryRenderer extends HqlBaseVisitor<QueryTokenStream> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitFromRoot(HqlParser.FromRootContext ctx) {
|
||||
public QueryTokenStream visitRootEntity(HqlParser.RootEntityContext ctx) {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
if (ctx.entityName() != null) {
|
||||
builder.appendExpression(visit(ctx.entityName()));
|
||||
|
||||
builder.appendExpression(visit(ctx.entityName()));
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
|
||||
} else if (ctx.subquery() != null) {
|
||||
|
||||
if (ctx.LATERAL() != null) {
|
||||
builder.append(QueryTokens.expression(ctx.LATERAL()));
|
||||
}
|
||||
|
||||
QueryRendererBuilder nested = QueryRenderer.builder();
|
||||
|
||||
nested.append(TOKEN_OPEN_PAREN);
|
||||
nested.appendInline(visit(ctx.subquery()));
|
||||
nested.append(TOKEN_CLOSE_PAREN);
|
||||
|
||||
builder.appendExpression(nested);
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
|
||||
} else if (ctx.functionCallAsFromSource() != null) {
|
||||
|
||||
builder.appendExpression(visit(ctx.functionCallAsFromSource()));
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitRootSubquery(HqlParser.RootSubqueryContext ctx) {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
if (ctx.LATERAL() != null) {
|
||||
builder.append(QueryTokens.expression(ctx.LATERAL()));
|
||||
}
|
||||
|
||||
QueryRendererBuilder nested = QueryRenderer.builder();
|
||||
|
||||
nested.append(TOKEN_OPEN_PAREN);
|
||||
nested.appendInline(visit(ctx.subquery()));
|
||||
nested.append(TOKEN_CLOSE_PAREN);
|
||||
|
||||
builder.appendExpression(nested);
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitRootFunction(HqlParser.RootFunctionContext ctx) {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
builder.appendExpression(visit(ctx.setReturningFunction()));
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitSetReturningFunction(HqlParser.SetReturningFunctionContext ctx) {
|
||||
return visit(ctx.simpleSetReturningFunction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitSimpleSetReturningFunction(HqlParser.SimpleSetReturningFunctionContext ctx) {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
builder.append(visit(ctx.identifier()));
|
||||
|
||||
builder.append(TOKEN_OPEN_PAREN);
|
||||
if (ctx.genericFunctionArguments() != null) {
|
||||
builder.append(visit(ctx.genericFunctionArguments()));
|
||||
}
|
||||
builder.append(TOKEN_CLOSE_PAREN);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitJoin(HqlParser.JoinContext ctx) {
|
||||
|
||||
@@ -459,7 +471,7 @@ class HqlQueryRenderer extends HqlBaseVisitor<QueryTokenStream> {
|
||||
}
|
||||
|
||||
builder.append(TOKEN_OPEN_PAREN);
|
||||
builder.append(visit(ctx.subquery()));
|
||||
builder.appendInline(visit(ctx.subquery()));
|
||||
builder.append(TOKEN_CLOSE_PAREN);
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
@@ -474,7 +486,7 @@ class HqlQueryRenderer extends HqlBaseVisitor<QueryTokenStream> {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
builder.append(visit(ctx.functionCallAsJoinTarget()));
|
||||
builder.append(visit(ctx.setReturningFunction()));
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
builder.appendExpression(visit(ctx.variable()));
|
||||
@@ -484,24 +496,6 @@ class HqlQueryRenderer extends HqlBaseVisitor<QueryTokenStream> {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitFunctionCallAsJoinTarget(HqlParser.FunctionCallAsJoinTargetContext ctx) {
|
||||
|
||||
QueryRendererBuilder builder = QueryRenderer.builder();
|
||||
|
||||
builder.append(visit(ctx.identifier()));
|
||||
|
||||
builder.append(TOKEN_OPEN_PAREN);
|
||||
|
||||
if (!ctx.expression().isEmpty()) {
|
||||
builder.append(QueryTokenStream.concatExpressions(ctx.expression(), this::visit, TOKEN_COMMA));
|
||||
}
|
||||
|
||||
builder.append(TOKEN_CLOSE_PAREN);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTokenStream visitUpdateStatement(HqlParser.UpdateStatementContext ctx) {
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Christoph Strobl
|
||||
* @author oscar.fanchin
|
||||
* @author Oscar Fanchin
|
||||
* @since 3.1
|
||||
*/
|
||||
@SuppressWarnings("ConstantValue")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -36,7 +36,7 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Yannick Brandt
|
||||
* @author oscar.fanchin
|
||||
* @author Oscar Fanchin
|
||||
* @since 3.1
|
||||
*/
|
||||
class HqlQueryRendererTests {
|
||||
@@ -608,8 +608,8 @@ class HqlQueryRendererTests {
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EXISTS (SELECT spouseEmp
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -620,14 +620,14 @@ class HqlQueryRendererTests {
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EVERY (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ALL (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -656,14 +656,14 @@ class HqlQueryRendererTests {
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE ANY (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE SOME (SELECT spouseEmp
|
||||
FROM Employee spouseEmp) > 1
|
||||
FROM Employee spouseEmp) > 1
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -772,7 +772,7 @@ class HqlQueryRendererTests {
|
||||
assertQuery("""
|
||||
SELECT s.name, COUNT(p)
|
||||
FROM Suppliers s LEFT JOIN s.products p
|
||||
ON p.status = 'inStock'
|
||||
ON p.status = 'inStock'
|
||||
GROUP BY s.name
|
||||
""");
|
||||
}
|
||||
@@ -854,15 +854,15 @@ class HqlQueryRendererTests {
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.projects p
|
||||
WHERE TREAT(p AS LargeProject).budget > 1000
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE "cost overrun"
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE "cost overrun"
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.projects p
|
||||
WHERE TREAT(p AS LargeProject).budget > 1000
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE 'cost overrun'
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE 'cost overrun'
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -872,7 +872,7 @@ class HqlQueryRendererTests {
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE TREAT(e AS Exempt).vacationDays > 10
|
||||
OR TREAT(e AS Contractor).hours > 100
|
||||
OR TREAT(e AS Contractor).hours > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -883,8 +883,8 @@ class HqlQueryRendererTests {
|
||||
SELECT emp
|
||||
FROM Employee emp
|
||||
WHERE emp.salary > ALL (SELECT m.salary
|
||||
FROM Manager m
|
||||
WHERE m.department = emp.department)
|
||||
FROM Manager m
|
||||
WHERE m.department = emp.department)
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -895,8 +895,8 @@ class HqlQueryRendererTests {
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EXISTS (SELECT spouseEmp
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -970,9 +970,9 @@ class HqlQueryRendererTests {
|
||||
UPDATE Employee e
|
||||
SET e.salary =
|
||||
CASE WHEN e.rating = 1 THEN e.salary * 1.1
|
||||
WHEN e.rating = 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
WHEN e.rating = 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -982,10 +982,10 @@ class HqlQueryRendererTests {
|
||||
assertQuery("""
|
||||
UPDATE Employee e
|
||||
SET e.salary =
|
||||
CASE e.rating WHEN 1 THEN e.salary * 1.1
|
||||
WHEN 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
CASE e.rating WHEN 1 THEN e.salary * 1.1
|
||||
WHEN 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -994,11 +994,11 @@ class HqlQueryRendererTests {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.name,
|
||||
CASE TYPE(e) WHEN Exempt THEN 'Exempt'
|
||||
WHEN Contractor THEN 'Contractor'
|
||||
WHEN Intern THEN 'Intern'
|
||||
ELSE 'NonExempt'
|
||||
END
|
||||
CASE TYPE(e) WHEN Exempt THEN 'Exempt'
|
||||
WHEN Contractor THEN 'Contractor'
|
||||
WHEN Intern THEN 'Intern'
|
||||
ELSE 'NonExempt'
|
||||
END
|
||||
FROM Employee e
|
||||
WHERE e.dept.name = 'Engineering'
|
||||
""");
|
||||
@@ -1009,12 +1009,12 @@ class HqlQueryRendererTests {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.name,
|
||||
f.name,
|
||||
CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum '
|
||||
WHEN f.annualMiles > 25000 THEN 'Gold '
|
||||
ELSE ''
|
||||
END,
|
||||
'Frequent Flyer')
|
||||
f.name,
|
||||
CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum '
|
||||
WHEN f.annualMiles > 25000 THEN 'Gold '
|
||||
ELSE ''
|
||||
END,
|
||||
'Frequent Flyer')
|
||||
FROM Employee e JOIN e.frequentFlierPlan f
|
||||
""");
|
||||
}
|
||||
@@ -1104,8 +1104,8 @@ class HqlQueryRendererTests {
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE EXISTS (SELECT c2
|
||||
FROM Customer c2
|
||||
WHERE c2.orders %s c.orders)
|
||||
FROM Customer c2
|
||||
WHERE c2.orders %s c.orders)
|
||||
""".formatted(distinctFrom));
|
||||
}
|
||||
|
||||
@@ -1814,12 +1814,12 @@ class HqlQueryRendererTests {
|
||||
"from Person pr " + //
|
||||
"left join pr.phones ph " + //
|
||||
"where ph is null " + //
|
||||
" or ph.type = :phoneType");
|
||||
"or ph.type = :phoneType");
|
||||
assertQuery("select distinct pr " + //
|
||||
"from Person pr " + //
|
||||
"left outer join pr.phones ph " + //
|
||||
"where ph is null " + //
|
||||
" or ph.type = :phoneType");
|
||||
"or ph.type = :phoneType");
|
||||
assertQuery("select pr.name, ph.number " + //
|
||||
"from Person pr " + //
|
||||
"left join pr.phones ph with ph.type = :phoneType ");
|
||||
@@ -1843,8 +1843,7 @@ class HqlQueryRendererTests {
|
||||
"(select c.duration as duration " + //
|
||||
" from p.calls c" + //
|
||||
" order by c.duration desc" + //
|
||||
" limit 1 " + //
|
||||
" ) longest " + //
|
||||
" limit 1) longest " + //
|
||||
"where p.number = :phoneNumber");
|
||||
assertQuery("select ph " + //
|
||||
"from Phone ph " + //
|
||||
@@ -2208,7 +2207,7 @@ class HqlQueryRendererTests {
|
||||
SELECT b
|
||||
FROM MyEntity b
|
||||
WHERE b.status = :status
|
||||
AND utl_raw.cast_to_varchar2((nlssort(lower(b.name), 'nls_sort=binary_ai'))) LIKE lower(:name)
|
||||
AND utl_raw.cast_to_varchar2((nlssort(lower(b.name), 'nls_sort=binary_ai'))) LIKE lower(:name)
|
||||
ORDER BY utl_raw.cast_to_varchar2((nlssort(lower(b.name), 'nls_sort=binary_ai'))) ASC
|
||||
""");
|
||||
|
||||
@@ -2377,17 +2376,17 @@ class HqlQueryRendererTests {
|
||||
assertQuery("select ie from ItemExample ie where ie.status = com.app.domain.object.Status.UP");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function (SRF) support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void fromSRFWithAlias() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue ) d
|
||||
from some_function(:date, :integerValue) d
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date ) d
|
||||
from some_function(:date) d
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -2397,21 +2396,21 @@ class HqlQueryRendererTests {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue , :longValue ) d
|
||||
from some_function(:date, :integerValue, :longValue) d
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void fromSRFWithoutAlias() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue )
|
||||
from some_function(:date, :integerValue)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date )
|
||||
from some_function(:date)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -2421,21 +2420,21 @@ class HqlQueryRendererTests {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue , :longValue )
|
||||
from some_function(:date, :integerValue, :longValue)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void joinEntityToSRFWithFunctionAlias() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from EntityClass e join some_function(:date , :integerValue ) d on (e.id = d.idFunction)
|
||||
from EntityClass e join some_function(:date, :integerValue) d on (e.id = d.idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from EntityClass e join some_function(:date ) d on (e.id = d.idFunction)
|
||||
from EntityClass e join some_function(:date) d on (e.id = d.idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -2443,24 +2442,23 @@ class HqlQueryRendererTests {
|
||||
from EntityClass e join some_function() d on (e.id = d.idFunction)
|
||||
""");
|
||||
|
||||
assertQuery(
|
||||
"""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from EntityClass e join some_function(:date , :integerValue , :longValue ) d on (e.id = d.idFunction)
|
||||
""");
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from EntityClass e join some_function(:date, :integerValue, :longValue) d on (e.id = d.idFunction)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void joinEntityToSRFWithoutFunctionAlias() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from EntityClass e join some_function(:date , :integerValue ) on (e.id = idFunction)
|
||||
from EntityClass e join some_function(:date, :integerValue) on (e.id = idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from EntityClass e join some_function(:date ) on (e.id = idFunction)
|
||||
from EntityClass e join some_function(:date) on (e.id = idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -2470,21 +2468,21 @@ class HqlQueryRendererTests {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from EntityClass e join some_function(:date , :integerValue , :longValue ) on (e.id = idFunction)
|
||||
from EntityClass e join some_function(:date, :integerValue, :longValue) on (e.id = idFunction)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void joinSRFToEntityWithoutFunctionWithAlias() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue ) d join EntityClass e on (e.id = d.idFunction)
|
||||
from some_function(:date, :integerValue) d join EntityClass e on (e.id = d.idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date ) d join EntityClass e on (e.id = idFunction)
|
||||
from some_function(:date) d join EntityClass e on (e.id = idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -2493,22 +2491,22 @@ class HqlQueryRendererTests {
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue , :longValue ) d join EntityClass e on (e.id = d.idFunction)
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date, :integerValue, :longValue) d join EntityClass e on (e.id = d.idFunction)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void joinSRFToEntityWithoutFunctionWithoutAlias() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue ) join EntityClass e on (e.id = idFunction)
|
||||
from some_function(:date, :integerValue) join EntityClass e on (e.id = idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date ) join EntityClass e on (e.id = idFunction)
|
||||
from some_function(:date) join EntityClass e on (e.id = idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -2518,23 +2516,23 @@ class HqlQueryRendererTests {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue , :longValue ) join EntityClass e on (e.id = idFunction)
|
||||
from some_function(:date, :integerValue, :longValue) join EntityClass e on (e.id = idFunction)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void selectSRFIntoSubquery() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date , :integerValue ) x) d
|
||||
from some_function(:date, :integerValue) x) d
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date ) x) d
|
||||
from some_function(:date) x) d
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
@@ -2546,82 +2544,82 @@ class HqlQueryRendererTests {
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date , :integerValue , :longValue ) x) d
|
||||
from some_function(:date, :integerValue, :longValue) x) d
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void joinEntityToSRFIntoSubquery() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date , :integerValue ) x ) d on (k.id = d.idFunction)
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date, :integerValue) x) d on (k.id = d.idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date ) x ) d on (k.id = d.idFunction)
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date) x) d on (k.id = d.idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function() x ) d on (k.id = d.idFunction)
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function() x) d on (k.id = d.idFunction)
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date , :integerValue , :longValue ) x ) d on (k.id = d.idFunction)
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
inner join (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date, :integerValue, :longValue) x) d on (k.id = d.idFunction)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void joinLateralEntityToSRF() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date , :integerValue ) x where x.idFunction = k.id ) d
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date, :integerValue) x where x.idFunction = k.id) d
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date ) x where x.idFunction = k.id ) d
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date) x where x.idFunction = k.id) d
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function() x where x.idFunction = k.id ) d
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function() x where x.idFunction = k.id) d
|
||||
""");
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date , :integerValue , :longValue ) x where x.idFunction = k.id ) d
|
||||
select new com.example.dto.SampleDto(k.id, d.nameFunction)
|
||||
from EntityClass k
|
||||
join lateral (select x.idFunction idFunction, x.nameFunction nameFunction
|
||||
from some_function(:date, :integerValue, :longValue) x where x.idFunction = k.id) d
|
||||
""");
|
||||
|
||||
}
|
||||
|
||||
@Test // GH-3864 - Added support for Set Return function support H7 parsing and
|
||||
// rendering
|
||||
@Test // GH-3864
|
||||
void joinTwoFunctions() {
|
||||
|
||||
assertQuery("""
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date , :integerValue ) d
|
||||
inner join some_function_single_param(:date ) k on (d.idFunction = k.idFunctionSP)
|
||||
select new com.example.dto.SampleDto(d.idFunction, d.nameFunction)
|
||||
from some_function(:date, :integerValue) d
|
||||
inner join some_function_single_param(:date) k on (d.idFunction = k.idFunctionSP)
|
||||
""");
|
||||
|
||||
}
|
||||
|
||||
@@ -1133,32 +1133,31 @@ class HqlQueryTransformerTests {
|
||||
assertCountQuery("select distinct substring(e.firstname, 1, position('a' in e.lastname)) as x from from Employee",
|
||||
"select count(distinct substring(e.firstname, 1, position('a' in e.lastname))) from from Employee");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test // GH-3864
|
||||
void testCountFromFunctionWithAlias() {
|
||||
|
||||
// given
|
||||
var original = "select x.id, x.value from some_function(:date , :integerValue ) x";
|
||||
var original = "select x.id, x.value from some_function(:date, :integerValue) x";
|
||||
|
||||
// when
|
||||
var results = createCountQueryFor(original);
|
||||
|
||||
// then
|
||||
assertThat(results).contains("select count(*) from some_function(:date , :integerValue ) x");
|
||||
}
|
||||
|
||||
assertThat(results).contains("select count(*) from some_function(:date, :integerValue) x");
|
||||
}
|
||||
|
||||
@Test // GH-3864
|
||||
void testCountFromFunctionNoAlias() {
|
||||
|
||||
// given
|
||||
var original = "select id, value from some_function(:date , :integerValue )";
|
||||
var original = "select id, value from some_function(:date, :integerValue)";
|
||||
|
||||
// when
|
||||
var results = createCountQueryFor(original);
|
||||
|
||||
// then
|
||||
assertThat(results).contains("select count(*) from some_function(:date , :integerValue )");
|
||||
assertThat(results).contains("select count(*) from some_function(:date, :integerValue)");
|
||||
}
|
||||
|
||||
@Test // GH-3427
|
||||
|
||||
Reference in New Issue
Block a user