Type:
Task
Priority:
Critical
Resolution:
Fixed
One can use UNION DISTINCT as an easy way of avoiding cycles when traversing a graph with a CTE:
WITH RECURSIVE cte (from_, to_) (
SELECT 1,1
UNION DISTINCT
SELECT graph.from_, graph.to_ FROM graph, cte WHERE graph.from_ = cte.to_
) ...
But often one needs to know more than edges, for example
WITH RECURSIVE cte (depth, from_, to_) (
SELECT 0,1,1
UNION DISTINCT
SELECT depth+1, graph.from_, graph.to_ FROM graph, cte WHERE graph.from_ = cte.to_
) ...
and here DISTINCT no longer works.
SQL Standard specifies that a CTE can have a CYCLE clause as
WITH RECURSIVE ... (
...
)
CYCLE <cycle column list>
SET <cycle mark column> TO <cycle mark value> DEFAULT <non-cycle mark value>
USING <path column>
where
<cycle column list> is a subset of columns that the CTE returns
<cycle mark column> is a new column, generated on the fly, its value for any particular row being <cycle mark value> if there's a cycle and <non-cycle mark value> if there's no cycle
<path column> is an ARRAY where the path is being accumulated
While in the standard all clauses in the CYCLE are mandatory, we'll relax this grammar to allow only CYCLE <cycle column list> .
This task is about implementing optional CYCLE <cycle column list> clause after the recursive CTE definition.
There is a simple way to implement it by changing CTE's UNION ALL or UNION DISTINCT operator to enforce distinct-ness only over <cycle column list> columns, not over all columns that CTE returns.
The example from above would look like
WITH RECURSIVE cte (depth, from_, to_) (
SELECT 0,1,1
UNION
SELECT depth+1, graph.from_, graph.to_ FROM graph, cte WHERE graph.from_ = cte.to_
) CYCLE from_, to_ RESTRICT
...
Note that it doesn't matter whether the CTE uses UNION ALL or UNION DISTINCT anymore. UNION ALL means "all rows, but without cycles", which is exactly what we'll do. And UNION DISTINCT means all rows should be different, which, again, is what will happen — as we'll enforce uniqueness over a subset of columns, complete rows will automatically be all different.
causes
MDEV-22018
WITH RECURSIVE supports CYCLE clause, but it is not documented
Closed
{"report":{"fcp":888.7999992370605,"ttfb":180.29999923706055,"pageVisibility":"visible","entityId":79087,"key":"jira.project.issue.view-issue","isInitial":true,"threshold":1000,"elementTimings":{},"userDeviceMemory":8,"userDeviceProcessors":64,"apdex":1,"journeyId":"d3da522d-9e49-4e0c-a7b6-aa3f05913f6e","navigationType":0,"readyForUser":971.2999992370605,"redirectCount":0,"resourceLoadedEnd":930.0999994277954,"resourceLoadedStart":187.29999923706055,"resourceTiming":[{"duration":113.40000057220459,"initiatorType":"link","name":"https://jira.mariadb.org/s/2c21342762a6a02add1c328bed317ffd-CDN/lu2bv2/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/css/_super/batch.css","startTime":187.29999923706055,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":187.29999923706055,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":300.69999980926514,"responseStart":0,"secureConnectionStart":0},{"duration":113.40000057220459,"initiatorType":"link","name":"https://jira.mariadb.org/s/7ebd35e77e471bc30ff0eba799ebc151-CDN/lu2bv2/820016/12ta74/2380add21a9a1006587582385952de73/_/download/contextbatch/css/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.css?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&slack-enabled=true","startTime":187.5999994277954,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":187.5999994277954,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":301,"responseStart":0,"secureConnectionStart":0},{"duration":184,"initiatorType":"script","name":"https://jira.mariadb.org/s/e9b27a47da5fb0f74a35acd57e9847fb-CDN/lu2bv2/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/js/_super/batch.js?locale=en","startTime":187.69999980926514,"connectEnd":187.69999980926514,"connectStart":187.69999980926514,"domainLookupEnd":187.69999980926514,"domainLookupStart":187.69999980926514,"fetchStart":187.69999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":187.69999980926514,"responseEnd":371.69999980926514,"responseStart":371.69999980926514,"secureConnectionStart":187.69999980926514},{"duration":243.80000019073486,"initiatorType":"script","name":"https://jira.mariadb.org/s/c32eb0da7ad9831253f8397e6cc26afd-CDN/lu2bv2/820016/12ta74/2380add21a9a1006587582385952de73/_/download/contextbatch/js/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&locale=en&slack-enabled=true","startTime":187.89999961853027,"connectEnd":187.89999961853027,"connectStart":187.89999961853027,"domainLookupEnd":187.89999961853027,"domainLookupStart":187.89999961853027,"fetchStart":187.89999961853027,"redirectEnd":0,"redirectStart":0,"requestStart":187.89999961853027,"responseEnd":431.69999980926514,"responseStart":431.69999980926514,"secureConnectionStart":187.89999961853027},{"duration":247,"initiatorType":"script","name":"https://jira.mariadb.org/s/bc0bcb146314416123c992714ee00ff7-CDN/lu2bv2/820016/12ta74/c92c0caa9a024ae85b0ebdbed7fb4bd7/_/download/contextbatch/js/atl.global,-_super/batch.js?locale=en","startTime":188.0999994277954,"connectEnd":188.0999994277954,"connectStart":188.0999994277954,"domainLookupEnd":188.0999994277954,"domainLookupStart":188.0999994277954,"fetchStart":188.0999994277954,"redirectEnd":0,"redirectStart":0,"requestStart":188.0999994277954,"responseEnd":435.0999994277954,"responseStart":435.0999994277954,"secureConnectionStart":188.0999994277954},{"duration":247.19999980926514,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-en/jira.webresources:calendar-en.js","startTime":188.39999961853027,"connectEnd":188.39999961853027,"connectStart":188.39999961853027,"domainLookupEnd":188.39999961853027,"domainLookupStart":188.39999961853027,"fetchStart":188.39999961853027,"redirectEnd":0,"redirectStart":0,"requestStart":188.39999961853027,"responseEnd":435.5999994277954,"responseStart":435.5999994277954,"secureConnectionStart":188.39999961853027},{"duration":247.4000005722046,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-localisation-moment/jira.webresources:calendar-localisation-moment.js","startTime":188.5999994277954,"connectEnd":188.5999994277954,"connectStart":188.5999994277954,"domainLookupEnd":188.5999994277954,"domainLookupStart":188.5999994277954,"fetchStart":188.5999994277954,"redirectEnd":0,"redirectStart":0,"requestStart":188.5999994277954,"responseEnd":436,"responseStart":436,"secureConnectionStart":188.5999994277954},{"duration":327.20000076293945,"initiatorType":"link","name":"https://jira.mariadb.org/s/b04b06a02d1959df322d9cded3aeecc1-CDN/lu2bv2/820016/12ta74/a2ff6aa845ffc9a1d22fe23d9ee791fc/_/download/contextbatch/css/jira.global.look-and-feel,-_super/batch.css","startTime":188.79999923706055,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":188.79999923706055,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":516,"responseStart":0,"secureConnectionStart":0},{"duration":247.5,"initiatorType":"script","name":"https://jira.mariadb.org/rest/api/1.0/shortcuts/820016/47140b6e0a9bc2e4913da06536125810/shortcuts.js?context=issuenavigation&context=issueaction","startTime":189,"connectEnd":189,"connectStart":189,"domainLookupEnd":189,"domainLookupStart":189,"fetchStart":189,"redirectEnd":0,"redirectStart":0,"requestStart":189,"responseEnd":436.5,"responseStart":436.5,"secureConnectionStart":189},{"duration":327,"initiatorType":"link","name":"https://jira.mariadb.org/s/3ac36323ba5e4eb0af2aa7ac7211b4bb-CDN/lu2bv2/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/css/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.css?jira.create.linked.issue=true","startTime":189.0999994277954,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":189.0999994277954,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":516.0999994277954,"responseStart":0,"secureConnectionStart":0},{"duration":248,"initiatorType":"script","name":"https://jira.mariadb.org/s/719848dd97ebe0663199f49a3936487a-CDN/lu2bv2/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/js/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.js?jira.create.linked.issue=true&locale=en","startTime":189.19999980926514,"connectEnd":189.19999980926514,"connectStart":189.19999980926514,"domainLookupEnd":189.19999980926514,"domainLookupStart":189.19999980926514,"fetchStart":189.19999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":189.19999980926514,"responseEnd":437.19999980926514,"responseStart":437.19999980926514,"secureConnectionStart":189.19999980926514},{"duration":397.0999994277954,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-js/jira.webresources:bigpipe-js.js","startTime":190.19999980926514,"connectEnd":190.19999980926514,"connectStart":190.19999980926514,"domainLookupEnd":190.19999980926514,"domainLookupStart":190.19999980926514,"fetchStart":190.19999980926514,"redirectEnd":0,"redirectStart":0,"requestStart":190.19999980926514,"responseEnd":587.2999992370605,"responseStart":587.2999992370605,"secureConnectionStart":190.19999980926514},{"duration":428.6000003814697,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-init/jira.webresources:bigpipe-init.js","startTime":190.29999923706055,"connectEnd":190.29999923706055,"connectStart":190.29999923706055,"domainLookupEnd":190.29999923706055,"domainLookupStart":190.29999923706055,"fetchStart":190.29999923706055,"redirectEnd":0,"redirectStart":0,"requestStart":190.29999923706055,"responseEnd":618.8999996185303,"responseStart":618.8999996185303,"secureConnectionStart":190.29999923706055},{"duration":77.89999961853027,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":527,"connectEnd":527,"connectStart":527,"domainLookupEnd":527,"domainLookupStart":527,"fetchStart":527,"redirectEnd":0,"redirectStart":0,"requestStart":527,"responseEnd":604.8999996185303,"responseStart":604.8999996185303,"secureConnectionStart":527},{"duration":78.60000038146973,"initiatorType":"link","name":"https://jira.mariadb.org/s/d5715adaadd168a9002b108b2b039b50-CDN/lu2bv2/820016/12ta74/be4b45e9cec53099498fa61c8b7acba4/_/download/contextbatch/css/jira.project.sidebar,-_super,-project.issue.navigator,-jira.general,-jira.browse.project,-jira.view.issue,-jira.global,-atl.general,-com.atlassian.jira.projects.sidebar.init/batch.css?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&slack-enabled=true","startTime":801.7999992370605,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":801.7999992370605,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":880.3999996185303,"responseStart":0,"secureConnectionStart":0},{"duration":123,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/e65b778d185daf5aee24936755b43da6/_/download/contextbatch/js/browser-metrics-plugin.contrib,-_super,-project.issue.navigator,-jira.view.issue,-atl.general/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&slack-enabled=true","startTime":802.6999998092651,"connectEnd":802.6999998092651,"connectStart":802.6999998092651,"domainLookupEnd":802.6999998092651,"domainLookupStart":802.6999998092651,"fetchStart":802.6999998092651,"redirectEnd":0,"redirectStart":0,"requestStart":802.6999998092651,"responseEnd":925.6999998092651,"responseStart":925.6999998092651,"secureConnectionStart":802.6999998092651},{"duration":127,"initiatorType":"script","name":"https://jira.mariadb.org/s/53a43b6764f587426c7bb9a150184c00-CDN/lu2bv2/820016/12ta74/be4b45e9cec53099498fa61c8b7acba4/_/download/contextbatch/js/jira.project.sidebar,-_super,-project.issue.navigator,-jira.general,-jira.browse.project,-jira.view.issue,-jira.global,-atl.general,-com.atlassian.jira.projects.sidebar.init/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&locale=en&slack-enabled=true","startTime":803.0999994277954,"connectEnd":803.0999994277954,"connectStart":803.0999994277954,"domainLookupEnd":803.0999994277954,"domainLookupStart":803.0999994277954,"fetchStart":803.0999994277954,"redirectEnd":0,"redirectStart":0,"requestStart":803.0999994277954,"responseEnd":930.0999994277954,"responseStart":930.0999994277954,"secureConnectionStart":803.0999994277954},{"duration":130.60000038146973,"initiatorType":"script","name":"https://www.google-analytics.com/analytics.js","startTime":879.8999996185303,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":879.8999996185303,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":1010.5,"responseStart":0,"secureConnectionStart":0},{"duration":77.09999942779541,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":1008.6999998092651,"connectEnd":1008.6999998092651,"connectStart":1008.6999998092651,"domainLookupEnd":1008.6999998092651,"domainLookupStart":1008.6999998092651,"fetchStart":1008.6999998092651,"redirectEnd":0,"redirectStart":0,"requestStart":1008.6999998092651,"responseEnd":1085.7999992370605,"responseStart":1085.7999992370605,"secureConnectionStart":1008.6999998092651}],"fetchStart":1,"domainLookupStart":1,"domainLookupEnd":1,"connectStart":1,"connectEnd":1,"requestStart":4,"responseStart":181,"responseEnd":185,"domLoading":185,"domInteractive":1040,"domContentLoadedEventStart":1040,"domContentLoadedEventEnd":1083,"domComplete":1276,"loadEventStart":1276,"loadEventEnd":1278,"userAgent":"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)","marks":[{"name":"bigPipe.sidebar-id.start","time":1012.6999998092651},{"name":"bigPipe.sidebar-id.end","time":1013.5},{"name":"bigPipe.activity-panel-pipe-id.start","time":1013.6999998092651},{"name":"bigPipe.activity-panel-pipe-id.end","time":1016.2999992370605},{"name":"activityTabFullyLoaded","time":1095}],"measures":[],"correlationId":"801c03fa2d456b","effectiveType":"4g","downlink":9,"rtt":0,"serverDuration":112,"dbReadsTimeInMs":14,"dbConnsTimeInMs":24,"applicationHash":"9d11dbea5f4be3d4cc21f03a88dd11d8c8687422","experiments":[]}}