-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DRAFT] fix: Use CTE in Enrollment analytics queries [DHIS-16705] #19519
base: master
Are you sure you want to change the base?
Conversation
|
||
void contributeCTE( | ||
ProgramIndicator programIndicator, | ||
RelationshipType relationshipType, |
Check notice
Code scanning / CodeQL
Useless parameter Note
...-analytics/src/main/java/org/hisp/dhis/analytics/common/ProgramIndicatorSubqueryBuilder.java
Fixed
Show fixed
Hide fixed
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
return fromClause.toString(); | ||
} | ||
|
||
protected String getSortClause(EventQueryParams params) { |
Check notice
Code scanning / CodeQL
Missing Override annotation Note
AbstractJdbcEventAnalyticsManager.getSortClause
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
.../hisp/dhis/analytics/event/data/programindicator/DefaultProgramIndicatorSubqueryBuilder.java
Fixed
Show fixed
Hide fixed
8c33952
to
3e070ce
Compare
5170115
to
d8119c0
Compare
...services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CTEContext.java
Fixed
Show fixed
Hide fixed
...services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CTEContext.java
Fixed
Show fixed
Hide fixed
...services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CTEContext.java
Fixed
Show fixed
Hide fixed
...services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CTEContext.java
Fixed
Show fixed
Hide fixed
...tics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManager.java
Fixed
Show fixed
Hide fixed
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
.../hisp/dhis/analytics/event/data/programindicator/DefaultProgramIndicatorSubqueryBuilder.java
Fixed
Show fixed
Hide fixed
5c4dba5
to
ef43c5b
Compare
...vices/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CteDefinition.java
Dismissed
Show dismissed
Hide dismissed
this.cteDefinition = cteDefinition; | ||
this.offsets.add(offset); | ||
// one alias per offset | ||
this.alias = new RandomStringGenerator.Builder().withinRange('a', 'z').build().generate(5); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
Builder.build
this.programIndicatorUid = programIndicatorUid; | ||
this.programStageUid = null; | ||
// ignore offset | ||
this.alias = new RandomStringGenerator.Builder().withinRange('a', 'z').build().generate(5); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
Builder.build
this.programIndicatorUid = null; | ||
this.programStageUid = programStageUid; | ||
// ignore offset | ||
this.alias = new RandomStringGenerator.Builder().withinRange('a', 'z').build().generate(5); |
Check notice
Code scanning / CodeQL
Deprecated method or constructor invocation Note
Builder.build
} | ||
|
||
if (offset < 0) { | ||
return (-1 * offset); |
Check failure
Code scanning / CodeQL
User-controlled data in arithmetic expression High
user-provided value
This arithmetic expression depends on a
user-provided value
This arithmetic expression depends on a
user-provided value
This arithmetic expression depends on a
user-provided value
This arithmetic expression depends on a
user-provided value
This arithmetic expression depends on a
user-provided value
This arithmetic expression depends on a
user-provided value
This arithmetic expression depends on a
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix AI about 3 hours ago
To fix the problem, we need to validate the offset
parameter before performing any arithmetic operations. Specifically, we should ensure that the offset
value is within a safe range to prevent overflow or underflow. We can achieve this by adding a guard clause that checks if the offset
value is within the range of Integer.MIN_VALUE
to Integer.MAX_VALUE
.
- Add a validation check for the
offset
parameter in thecomputeRowNumberOffset
method. - If the
offset
value is outside the safe range, we can either throw an exception or clamp the value to the nearest safe limit.
-
Copy modified lines R1330-R1332 -
Copy modified lines R1335-R1337
@@ -1329,4 +1329,10 @@ | ||
if (offset < 0) { | ||
if (offset == Integer.MIN_VALUE) { | ||
throw new IllegalArgumentException("Offset value is too small and may cause underflow."); | ||
} | ||
return (-1 * offset); | ||
} else { | ||
if (offset == Integer.MAX_VALUE) { | ||
throw new IllegalArgumentException("Offset value is too large and may cause overflow."); | ||
} | ||
return (offset - 1); |
aa533b4
to
5f05bb5
Compare
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
...services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CTEContext.java
Outdated
Show resolved
Hide resolved
...services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CTEContext.java
Outdated
Show resolved
Hide resolved
return ""; | ||
} | ||
|
||
StringBuilder sb = new StringBuilder("WITH "); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use lower-case for SQL keywords in Java, i.e. with
.
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Outdated
Show resolved
Hide resolved
...ces/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java
Outdated
Show resolved
Hide resolved
4e085d3
to
62c2237
Compare
void contributeCTE( | ||
ProgramIndicator programIndicator, | ||
RelationshipType relationshipType, | ||
AnalyticsType outerSqlEntity, |
Check notice
Code scanning / CodeQL
Useless parameter Note
/** | ||
* Returns a select SQL clause for the given query. | ||
* | ||
* @param params the {@link EventQueryParams}. | ||
*/ | ||
protected abstract String getSelectClause(EventQueryParams params); | ||
|
||
protected abstract String getColumnWithCte(QueryItem item, String suffix, CteContext cteContext); |
Check notice
Code scanning / CodeQL
Useless parameter Note
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
79f7563
to
94ab16e
Compare
sql = buildEnrollmentQueryWithCte(params); | ||
} | ||
|
||
System.out.println("SQL: " + sql); // FIXME: Remove debug line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove println.
// Using a text block with .formatted() for clarity: | ||
String join = | ||
""" | ||
LEFT JOIN %s %s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use lower-case keywords for SQL in Java.
...s-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/common/CTEUtils.java
Outdated
Show resolved
Hide resolved
import java.util.function.Predicate; | ||
import org.hisp.dhis.common.QueryFilter; | ||
|
||
/** Mimics the logic of @{@link org.hisp.dhis.common.InQueryFilter} to be used in CTEs */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove outer @.
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Show resolved
Hide resolved
params.getLatestEndDate(), | ||
cteContext); | ||
} else { | ||
programIndicatorSubqueryBuilder.contributeCTE( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename to contributeCte
.
bc234ee
to
a4ff98c
Compare
a4ff98c
to
e283b86
Compare
...alytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java
Fixed
Show fixed
Hide fixed
d2b4821
to
233220f
Compare
233220f
to
3e25880
Compare
Quality Gate failedFailed conditions See analysis details on SonarQube Cloud Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE |
WIP
Changes
This PR addresses the generation of SQL queries for Enrollment analytics
Problem
Currently, the Enrollment queries are structured so that sub-queries are used to fetch events values from the
analytics_event_*
tables.For instance:
The above query works in Postgres but does not work in Doris, because correlation with outer layers of the parent query is not supported.
Mitigation
The current approach is trying to refactor the Enrollment query so that the subqueries (both as select and as where conditions) are "moved" into CTE (Common Table Expressions).
Common Table Expressions are temporary result sets in SQL, defined within a
WITH
clause, that simplify complex queries by improving readability and modularizing logic. They are particularly useful for recursive queries and can be referenced multiple times within the main query.The above query can be rewritten like so:
The above query structure is compatible with Doris and it makes the execution of the query faster.
As a comparison:
Original query with sub-select
Refactored query with CTEs
Testing strategy
I am using the
e2e
project and aim at having 100% green tests on both Postgres and Doris.