]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add further tests for the BEGIN CONCURRENT extension on this branch.
authordan <Dan Kennedy>
Mon, 23 Feb 2026 11:42:16 +0000 (11:42 +0000)
committerdan <Dan Kennedy>
Mon, 23 Feb 2026 11:42:16 +0000 (11:42 +0000)
FossilOrigin-Name: eb09c021d3bfb55e0297180f8f76a0eee2233d8b09f4cd1e954b7ea501c66560

manifest
manifest.uuid
test/concurrentE.test [new file with mode: 0644]

index 862aaca7c46562a5fbdc5bb177d537a8f65804fb..19ce29227c96905f12c1047b72f06f08ecc8a841 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sOMIT_CONCURRENT\sbuilds\son\sthis\sbranch.
-D 2026-02-20T18:27:02.921
+C Add\sfurther\stests\sfor\sthe\sBEGIN\sCONCURRENT\sextension\son\sthis\sbranch.
+D 2026-02-23T11:42:16.203
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -1011,6 +1011,7 @@ F test/concurrentA.test 2272fecbf128ac5a8d7b0c9cfe732c4935a5a1b915e237c93ef8dce3
 F test/concurrentB.test b85e8adc4c1acf9b1cc0e8c2012348dc116d4ce032bb699d039f10de9b4cca71
 F test/concurrentC.test fd85071ee3792a1fe9c7faf5cdf70a338cdb1aeaa127ba6d1394db84b8fe0dbe
 F test/concurrentD.test ded9c6e975af21652717afb87c8632395610372bc276d1efa701af05233f0c69
+F test/concurrentE.test 590d6f496bc0fd2fa354ec1a913dde2c88ad38ba382fe7b4263caa0fce2fca3e
 F test/conflict.test 3307ffdf988e04b01c4e942d8aa369a977f085bf629f43a627c9a77f39d65926
 F test/conflict2.test 5557909ce683b1073982f5d1b61dfb1d41e369533bfdaf003180c5bc87282dd1
 F test/conflict3.test 81865d9599609aca394fb3b9cd5f561d4729ea5b176bece3644f6ecb540f88ac
@@ -2238,8 +2239,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 9202cd04f74ae69bb82c6574c2259d270ae35c9476cccc2e20f3c1f9c8a6c995
-R 5a7bc9e12a953155b053b6e3af37cb59
+P 461907251e63055b6ecb56ae8b687c6cead6bf0870a78d50855c54568e2f2391
+R 2f5a7668700f2f9dbb7c7efd461f47e5
 U dan
-Z 1f713f7a76b880e3040163159533c150
+Z 0c4d66a3f3d358a25605cdaaf8257b68
 # Remove this line to create a well-formed Fossil manifest.
index c3b9828d6b2874ca42366acdb877cce6ff5bb7d8..a41cbf59e8eace9ed2c91a42c1e45e89c7f42566 100644 (file)
@@ -1 +1 @@
-461907251e63055b6ecb56ae8b687c6cead6bf0870a78d50855c54568e2f2391
+eb09c021d3bfb55e0297180f8f76a0eee2233d8b09f4cd1e954b7ea501c66560
diff --git a/test/concurrentE.test b/test/concurrentE.test
new file mode 100644 (file)
index 0000000..f4d2732
--- /dev/null
@@ -0,0 +1,214 @@
+# 2026 February 23 
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix concurrentE
+
+db close
+sqlite3_shutdown
+#sqlite3_config_sharedlog_maxsize 0
+reset_db
+
+expr srand(0)
+
+do_execsql_test 1.0 {
+  PRAGMA journal_mode = wal2;
+  PRAGMA page_size = 512;
+  CREATE TABLE jobs(
+    jobID       INTEGER NOT NULL PRIMARY KEY,
+    parentJobID INTEGER NOT NULL DEFAULT 0,
+    state TEXT NOT NULL
+  );
+  CREATE INDEX jobs_idx ON jobs(parentJobID, state) WHERE parentJobID!=0;
+} {wal2}
+
+# Possible text values for jobs.state column
+#
+set lStateVal { FINISHED QUEUED RUNQUEUED RUNNING PAUSED }
+
+proc insert_job {db} {
+  set iParent [rand 0 10000000000]
+  $db eval { INSERT INTO jobs VALUES($iParent, 0, 'QUEUED'); }
+  set iParent [$db last_insert_rowid]
+  for {set ii 0} {$ii < 3} {incr ii} {
+    set iChild [rand 0 10000000000]
+    $db eval { INSERT INTO jobs VALUES($iChild, $iParent, 'QUEUED'); }
+  }
+}
+
+proc rand_state {} {
+  set lStateVal { FINISHED QUEUED RUNQUEUED RUNNING PAUSED }
+  lindex $lStateVal [rand 0 4]
+}
+db func rand_state rand_state
+
+proc rand {min max} {
+  expr {$min + int(abs(rand() * (1 + $max - $min)))}
+}
+db func rand rand
+
+# Each transaction is:
+#
+#   1. Select at random a child job to work on. Any child job with a state
+#      other than 'FINISHED' can be worked on. If no child job can be
+#      found, it is an error.
+#
+#   2. Open a transaction with BEGIN CONCURRENT.
+#
+#   3. Check that the child job is still available to work on.
+#
+#   4. Check parent job is not 'FINISHED' or missing. If it is, this is an
+#      error.
+#
+#   5. Set child job state to a randomly selected state.
+#
+#   6. check if there are any children of the parent with state set to
+#      anything other than FINISHED. If there are not, (a) set parent to 
+#      FINISHED, (b) add a new parent and its child jobs. All new jobs 
+#      entries are set to QUEUED state. jobid values are assigned randomly.
+#
+#   7. Commit transaction.
+#
+# This procedure does steps 1-6 of the above with
+#
+proc start_transaction {db} {
+  # Step 1: Choose a job to "work" on.
+  unset -nocomplain iChild iParent
+  $db eval {
+    WITH children(rownum, jobid, parentid, state) AS (
+      SELECT row_number() OVER (), jobid, parentjobid, state 
+      FROM jobs WHERE parentJobId!=0 AND state!='FINISHED'
+    )
+    SELECT jobid AS iChild, parentid AS iParent, state FROM children 
+    LIMIT 1 
+    OFFSET rand( 0, (SELECT count(*) FROM children)-1 );
+  } { }
+  if {[info exists iChild]==0} {
+    error "Could not find a child to work on!!!"
+  }
+
+  # Step 2: Open transaction.
+  $db eval { BEGIN CONCURRENT }
+
+  # Step 3: Check that our job is still available to work on. If it
+  # is not, close the transaction just opened and return zero. 
+  #
+  set child_ok 0
+  $db eval {
+    SELECT state IN ('QUEUED', 'RUNQUEUED', 'RUNNING', 'PAUSED')
+      FROM jobs 
+      WHERE jobId=$iChild
+  } {
+    set child_ok 1
+  }
+  if {$child_ok==0} {
+    $db eval { ROLLBACK }
+    return 0
+  }
+
+  # Step 4: Check parent is not finished or deleted.
+  set parent_ok 0
+  $db eval {
+    SELECT 
+      state IN ('QUEUED', 'RUNQUEUED', 'RUNNING', 'PAUSED')
+    FROM jobs 
+    WHERE jobId=$iParent
+  } {
+    set parent_ok 1
+  }
+  if {$parent_ok==0} {
+    error "Parent job is not in expected state!"
+  }
+
+  # Step 5: Update child job.
+  $db eval {
+    UPDATE jobs SET state=rand_state() WHERE jobid=$iChild
+  }
+
+  # Step 6: Check if all children of parent are finished. If so,
+  # set parent to FINISHED and add a new parent + child jobs.
+  # 
+  set iUnfinishedChild 0
+  $db eval {
+    SELECT jobId AS j FROM jobs 
+    WHERE parentJobID!=0 AND parentJobID=$iParent AND 
+      state IN ('QUEUED', 'RUNQUEUED', 'RUNNING', 'PAUSED')
+    LIMIT 1
+  } {
+    set iUnfinishedChild $j
+  }
+  if {$iUnfinishedChild==0} {
+    $db eval {
+      UPDATE jobs SET state = 'FINISHED' WHERE jobID = $iParent
+    }
+    insert_job $db
+  }
+
+  return 1
+}
+
+proc commit_transction {db} {
+  set rb [catch { $db eval COMMIT }]
+
+  if {$rb==0} {
+    incr ::O(commit)
+  } else {
+    catch { $db eval ROLLBACK }
+    incr ::O(rollback)
+  }
+}
+
+set ::O(commit) 0
+set ::O(rollback) 0
+
+set nInitialJob 8
+db eval BEGIN
+for {set ii 0} {$ii < $nInitialJob} {incr ii} {
+  insert_job db
+}
+db eval COMMIT
+
+set DBLIST [list db1 db2 db3 db4 db5 db6]
+foreach db $DBLIST {
+  sqlite3 $db test.db
+  $db func rand_state rand_state
+  $db func rand rand
+}
+
+for {set i 0} {$i < 1000} {incr i} {
+  foreach db $DBLIST {
+    start_transaction $db
+  }
+  foreach db $DBLIST {
+    commit_transction $db
+  }
+
+  db eval {
+    DELETE FROM jobs AS j WHERE 
+        (parentjobid=0 AND state='FINISHED') OR
+        (SELECT state FROM jobs WHERE jobID=j.parentJobID)='FINISHED'
+  }
+
+  do_execsql_test 1.$i { PRAGMA integrity_check } {ok}
+}
+
+foreach db $DBLIST {
+  $db close
+}
+
+do_execsql_test 1.x.c=$O(commit).r=$O(rollback) { SELECT 1 } 1
+
+
+finish_test
+