Skip to content

Commit 456abee

Browse files
feat: added scan query hint (#161)
1 parent f834908 commit 456abee

File tree

7 files changed

+194
-8
lines changed

7 files changed

+194
-8
lines changed

hibernate-dialect/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.1.0 ##
2+
3+
- Added hint for scan queries
4+
15
## 1.0.0 ##
26

37
- Fixed: data time type converters

hibernate-dialect/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>tech.ydb.dialects</groupId>
88
<artifactId>hibernate-ydb-dialect</artifactId>
9-
<version>1.0.0</version>
9+
<version>1.1.0</version>
1010

1111
<packaging>jar</packaging>
1212

hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/YdbDialect.java

+27-3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
import tech.ydb.hibernate.dialect.exporter.EmptyExporter;
5757
import tech.ydb.hibernate.dialect.exporter.YdbIndexExporter;
5858
import tech.ydb.hibernate.dialect.hint.IndexQueryHintHandler;
59+
import tech.ydb.hibernate.dialect.hint.QueryHintHandler;
60+
import tech.ydb.hibernate.dialect.hint.ScanQueryHintHandler;
5961
import tech.ydb.hibernate.dialect.translator.YdbSqlAstTranslatorFactory;
6062
import tech.ydb.hibernate.dialect.types.InstantJavaType;
6163
import tech.ydb.hibernate.dialect.types.InstantJdbcType;
@@ -72,6 +74,10 @@ public class YdbDialect extends Dialect {
7274

7375
private static final Exporter<ForeignKey> FOREIGN_KEY_EMPTY_EXPORTER = new EmptyExporter<>();
7476
private static final Exporter<Constraint> UNIQUE_KEY_EMPTY_EXPORTER = new EmptyExporter<>();
77+
private static final List<QueryHintHandler> QUERY_HINT_HANDLERS = List.of(
78+
IndexQueryHintHandler.INSTANCE,
79+
ScanQueryHintHandler.INSTANCE
80+
);
7581

7682
public YdbDialect(DialectResolutionInfo dialectResolutionInfo) {
7783
super(dialectResolutionInfo);
@@ -144,11 +150,29 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
144150
@Override
145151
public String addSqlHintOrComment(String sql, QueryOptions queryOptions, boolean commentsEnabled) {
146152
if (queryOptions.getDatabaseHints() != null) {
147-
sql = IndexQueryHintHandler.addQueryHints(sql, queryOptions.getDatabaseHints());
153+
for (var queryHintHandler : QUERY_HINT_HANDLERS) {
154+
sql = queryHintHandler.addQueryHints(sql, queryOptions.getDatabaseHints());
155+
}
148156
}
149157

150-
if (queryOptions.getComment() != null && IndexQueryHintHandler.commentIsHint(queryOptions.getComment())) {
151-
return IndexQueryHintHandler.addQueryHints(sql, List.of(queryOptions.getComment()));
158+
if (queryOptions.getComment() != null) {
159+
boolean commentIsHint = false;
160+
161+
var hints = queryOptions.getComment().split(",");
162+
163+
for (var queryHintHandler : QUERY_HINT_HANDLERS) {
164+
for (var hint : hints) {
165+
hint = hint.trim();
166+
if (queryHintHandler.commentIsHint(hint)) {
167+
commentIsHint = true;
168+
sql = queryHintHandler.addQueryHints(sql, List.of(hint));
169+
}
170+
}
171+
}
172+
173+
if (commentIsHint) {
174+
return sql;
175+
}
152176
}
153177

154178
if (commentsEnabled && queryOptions.getComment() != null) {

hibernate-dialect/src/main/java/tech/ydb/hibernate/dialect/hint/IndexQueryHintHandler.java

+11-4
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,24 @@
88
/**
99
* @author Kirill Kurdyukov
1010
*/
11-
public class IndexQueryHintHandler {
11+
public class IndexQueryHintHandler implements QueryHintHandler {
12+
public static final IndexQueryHintHandler INSTANCE = new IndexQueryHintHandler();
13+
1214
private static final Pattern SELECT_FROM_WHERE_QUERY_PATTERN = Pattern
1315
.compile("^\\s*(select.+?from\\s+\\w+)(.+where.+)$", Pattern.CASE_INSENSITIVE);
1416

15-
public static final String HINT_USE_INDEX = "use_index:";
17+
private static final String HINT_USE_INDEX = "use_index:";
18+
19+
private IndexQueryHintHandler() {
20+
}
1621

17-
public static boolean commentIsHint(String comment) {
22+
@Override
23+
public boolean commentIsHint(String comment) {
1824
return comment.startsWith(HINT_USE_INDEX);
1925
}
2026

21-
public static String addQueryHints(String query, List<String> hints) {
27+
@Override
28+
public String addQueryHints(String query, List<String> hints) {
2229
if (hints.isEmpty()) {
2330
return query;
2431
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package tech.ydb.hibernate.dialect.hint;
2+
3+
import java.util.List;
4+
5+
/**
6+
* @author Kirill Kurdyukov
7+
*/
8+
public interface QueryHintHandler {
9+
10+
String addQueryHints(String query, List<String> hints);
11+
12+
boolean commentIsHint(String comment);
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package tech.ydb.hibernate.dialect.hint;
2+
3+
import java.util.List;
4+
import java.util.concurrent.atomic.AtomicBoolean;
5+
6+
/**
7+
* @author Kirill Kurdyukov
8+
*/
9+
public class ScanQueryHintHandler implements QueryHintHandler {
10+
public static final ScanQueryHintHandler INSTANCE = new ScanQueryHintHandler();
11+
12+
private static final String HINT_USE_SCAN = "use_scan";
13+
14+
private ScanQueryHintHandler() {
15+
16+
}
17+
18+
@Override
19+
public String addQueryHints(String query, List<String> hints) {
20+
if (hints.isEmpty()) {
21+
return query;
22+
}
23+
24+
AtomicBoolean useScan = new AtomicBoolean(false);
25+
hints.forEach(hint -> {
26+
if (hint.equals(HINT_USE_SCAN)) {
27+
useScan.set(true);
28+
}
29+
});
30+
31+
if (useScan.get()) {
32+
return "scan " + query;
33+
}
34+
35+
return query;
36+
}
37+
38+
@Override
39+
public boolean commentIsHint(String comment) {
40+
return comment.startsWith(HINT_USE_SCAN);
41+
}
42+
}

hibernate-dialect/src/test/java/tech/ydb/hibernate/student/StudentsRepositoryTest.java

+96
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,100 @@ void sumAvgByStudentIdTest() {
260260
}
261261
);
262262
}
263+
264+
@Test
265+
void useScanQueryHintTest() {
266+
/*
267+
scan select
268+
c1_0.CourseId,
269+
c1_0.CourseName
270+
from
271+
Courses c1_0
272+
order by
273+
c1_0.CourseId
274+
*/
275+
inTransaction(
276+
session -> {
277+
var courses = session.createQuery("FROM Course c ORDER BY c.id", Course.class)
278+
.addQueryHint("use_scan")
279+
.getResultList();
280+
281+
checkCourses(courses);
282+
}
283+
);
284+
285+
/*
286+
scan select
287+
c1_0.CourseId,
288+
c1_0.CourseName
289+
from
290+
Courses c1_0
291+
order by
292+
c1_0.CourseId
293+
*/
294+
inTransaction(
295+
session -> {
296+
var courses = session.createQuery("FROM Course c ORDER BY c.id", Course.class)
297+
.setHint(HibernateHints.HINT_COMMENT, "use_scan")
298+
.getResultList();
299+
300+
checkCourses(courses);
301+
}
302+
);
303+
}
304+
305+
private static void checkCourses(List<Course> courses) {
306+
assertEquals(6, courses.size());
307+
assertEquals("Базы данных", courses.get(0).getName());
308+
assertEquals("Управление проектами", courses.get(1).getName());
309+
assertEquals("ППО", courses.get(2).getName());
310+
assertEquals("Теория информации", courses.get(3).getName());
311+
assertEquals("Математический анализ", courses.get(4).getName());
312+
assertEquals("Технологии Java", courses.get(5).getName());
313+
}
314+
315+
@Test
316+
void useIndexAndUseScanHintsTogetherTest() {
317+
/*
318+
scan select
319+
g1_0.GroupId,
320+
g1_0.GroupName
321+
from
322+
Groups view group_name_index g1_0
323+
where
324+
g1_0.GroupName='M3439'
325+
*/
326+
inTransaction(
327+
session -> {
328+
Group group = session
329+
.createQuery("FROM Group g WHERE g.name = 'M3439'", Group.class)
330+
.addQueryHint("use_index:group_name_index") // Hibernate
331+
.addQueryHint("use_scan")
332+
.getSingleResult();
333+
334+
assertEquals("M3439", group.getName());
335+
}
336+
);
337+
338+
339+
/*
340+
scan select
341+
g1_0.GroupId,
342+
g1_0.GroupName
343+
from
344+
Groups view group_name_index g1_0
345+
where
346+
g1_0.GroupName='M3439'
347+
*/
348+
inTransaction(
349+
session -> {
350+
Group group = session
351+
.createQuery("FROM Group g WHERE g.name = 'M3439'", Group.class)
352+
.setHint(HibernateHints.HINT_COMMENT, "use_index:group_name_index, use_scan") // JPA
353+
.getSingleResult();
354+
355+
assertEquals("M3439", group.getName());
356+
}
357+
);
358+
}
263359
}

0 commit comments

Comments
 (0)