0

I have recursive query on table with undirected graph data. Data is represented as table of edges (Oracle 11g). The recursive query traverses all edges starting from given edge. The idea of query is: given edge is at the 0th level and for n>0, edge is on n-th level if it incides with node of some so-far-unseen edge on (n-1)-th level.

with edges (id, a, b) as (
  select 1, 'X', 'Y' from dual union
  select 2, 'X', 'Y' from dual
), r (l, id, parent_a, parent_b, child_a, child_b, edge_seen) as (
  select 0, id, null, null, a, b, cast(collect(id) over () as sys.ku$_objnumset)
  from edges
  where id = 1 
  union all
  select r.l + 1, e.id, r.child_a, r.child_b, e.a, e.b
       , r.edge_seen multiset union distinct (cast(collect(e.id) over () as sys.ku$_objnumset))
  from r
  join edges e on (r.child_a in (e.a, e.b) or r.child_b in (e.a, e.b))
    and e.id not member of (select r.edge_seen from dual)
)
select * from r;

The query worked well until this situation with two edges between nodes occured:

+---+   1   +---+
|   |<----->|   |
| X |   2   | Y |
|   |<----->|   |
+---+       +---+

In this case, there is edge 1 on 0th level of recursion (initial row). I expected edge 2 would be added to result on 1st level of recursion since join condition holds. Instead I get "ORA-32044: cycle detected while executing recursive with query".

I know this error is reported when the row newly joined to recursive query result would be same as some existing row. What I don't understand is why Oracle treats row with same node ids but different edge id as duplicate. Adding cycle child_a, child_b set iscycle to 1 default 0 clause gives iscycle=1 for new row, adding cycle id, child_a, child_b set iscycle to 1 default 0 gives iscycle=0, which is both correct.

Why the error is produced and how to avoid it? (Note in Postgres (see fiddle) equivalent query works correctly.)

jps
  • 20,041
  • 15
  • 75
  • 79
Tomáš Záluský
  • 10,735
  • 2
  • 36
  • 64
  • I have access to Oracle 11.2.0.1, where your query throws ORA-32044, but it works in [dbfiddle](https://dbfiddle.uk/?rdbms=oracle_18&fiddle=c9459d119b05b4fbb7ba7b1a35a8bb48), Oracle 18.4.0.0. I made some minor correction, because dbfiddle has its limitations. – Ponder Stibbons Jul 10 '20 at 11:48
  • That's a bug and it was fixed in 12.1.0.2 – Sayan Malakshinov Jul 10 '20 at 11:55
  • It works in Oracle 11 if you add something like `and r.l < 100` to join condition as workaround. – Ponder Stibbons Jul 10 '20 at 12:02
  • @PonderStibbons ad 1st comment: Confirmed in Oracle 18. (My first thought was it had been caused by `sys.ku$_vcnt` collection but disproved - with custom collection it also doesn't work in Oracle 11.) Ad 2nd comment: Trick with `r.l < 100` works but only if I replace ANSI join with commas, i.e. `from r, edges e where (r.child_a in (e.a, e.b) or r.child_b in (e.a, e.b)) and e.id not member of (select r.edge_seen from dual) and r.l < 100000`. Don't know why, it resembles https://stackoverflow.com/q/62172579/653539 . Wouldn't you turn comment into answer? I don't like accepting own answers. :-) – Tomáš Záluský Jul 10 '20 at 14:05
  • @SayanMalakshinov I intuitively tend to agree with you. Do you have any link or sources to support this assertion? – Tomáš Záluský Jul 10 '20 at 14:08
  • Answer is highly dependent on Oracle versions, I do not know who and when corrected this bug. Anyway - what you are doing can be done with `cycle id set cycle to 'C' default '-'' [Cyclic Hierarchical Query](https://oracle-base.com/articles/11g/recursive-subquery-factoring-11gr2#cyclic). – Ponder Stibbons Jul 10 '20 at 14:09
  • @TomášZáluský The bug is hidden, if you want, you can ask support for the bug number, but Oracle 11.2 is EOL already, so just migrate to actual versions. – Sayan Malakshinov Jul 10 '20 at 14:11
  • yes, I'm aware of `cycle` clause, I was just hesitant to use workaround without knowing the root cause of this behaviour. The db is maintained by corporation I am subcontractor of, upgrade is not possible, unfortunately. Thanks to both responders. I will let the problem lie in my head over weekend and return to question on Monday. – Tomáš Záluský Jul 10 '20 at 14:20

0 Answers0