From e796da6e378128db23b9fbfe75a56409ef15d8da Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Wed, 26 Feb 2025 14:07:50 -0600 Subject: [PATCH] Prevent infinite recursion in queries --- .../todoroo/astrid/adapter/RecursiveLoopTest.kt | 4 ---- .../org/tasks/data/TaskListQueryRecursive.kt | 16 ++++++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/app/src/androidTest/java/com/todoroo/astrid/adapter/RecursiveLoopTest.kt b/app/src/androidTest/java/com/todoroo/astrid/adapter/RecursiveLoopTest.kt index fbb4e5991..03aa4c95e 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/adapter/RecursiveLoopTest.kt +++ b/app/src/androidTest/java/com/todoroo/astrid/adapter/RecursiveLoopTest.kt @@ -8,7 +8,6 @@ import dagger.hilt.android.testing.UninstallModules import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.tasks.data.TaskListQuery.getQuery import org.tasks.data.entity.Task @@ -35,7 +34,6 @@ class RecursiveLoopTest : InjectingTestCase() { } @Test - @Ignore("infinite loop") fun handleSelfLoop() = runBlocking { addTask(with(DUE_DATE, newDateTime()), with(PARENT, 1L)) @@ -46,7 +44,6 @@ class RecursiveLoopTest : InjectingTestCase() { } @Test - @Ignore("infinite loop") fun handleSingleLevelLoop() = runBlocking { val parent = addTask(with(DUE_DATE, newDateTime())) val child = addTask(with(PARENT, parent)) @@ -60,7 +57,6 @@ class RecursiveLoopTest : InjectingTestCase() { } @Test - @Ignore("infinite loop") fun handleMultiLevelLoop() = runBlocking { val parent = addTask(with(DUE_DATE, newDateTime())) val child = addTask(with(PARENT, parent)) diff --git a/kmp/src/commonMain/kotlin/org/tasks/data/TaskListQueryRecursive.kt b/kmp/src/commonMain/kotlin/org/tasks/data/TaskListQueryRecursive.kt index 3063aa852..68523f9e6 100644 --- a/kmp/src/commonMain/kotlin/org/tasks/data/TaskListQueryRecursive.kt +++ b/kmp/src/commonMain/kotlin/org/tasks/data/TaskListQueryRecursive.kt @@ -17,11 +17,6 @@ import org.tasks.preferences.QueryPreferences internal object TaskListQueryRecursive { private val RECURSIVE = Table("recursive_tasks") private val RECURSIVE_TASK = field("$RECURSIVE.task") - private val SUBTASK_QUERY = - QueryTemplate() - .join(Join.inner(RECURSIVE, Task.PARENT.eq(RECURSIVE_TASK))) - .where(activeAndVisible()) - .toString() fun getRecursiveQuery( filter: Filter, @@ -78,7 +73,8 @@ internal object TaskListQueryRecursive { ${SortHelper.orderSelectForSortTypeRecursive(groupMode, true)} AS primary_group, ${SortHelper.orderSelectForSortTypeRecursive(sortMode, false)} AS primary_sort, NULL as secondary_sort, - ${SortHelper.getSortGroup(groupMode)} AS sort_group + ${SortHelper.getSortGroup(groupMode)} AS sort_group, + '/' || tasks._id || '/' as recursive_path FROM tasks ${ if (groupMode == SortHelper.SORT_LIST) { @@ -104,9 +100,13 @@ internal object TaskListQueryRecursive { recursive_tasks.primary_group AS primary_group, recursive_tasks.primary_sort AS primary_sort, ${SortHelper.orderSelectForSortTypeRecursive(subtaskMode, false)} AS secondary_sort, - recursive_tasks.sort_group AS sort_group + recursive_tasks.sort_group AS sort_group, + recursive_tasks.recursive_path || tasks._id || '/' AS recursive_path FROM tasks - $SUBTASK_QUERY + INNER JOIN recursive_tasks ON tasks.parent = recursive_tasks.task + WHERE + ${activeAndVisible()} + AND recursive_tasks.recursive_path NOT LIKE '%/' || tasks._id || '/%' ORDER BY parent_complete, indent DESC,