exec-ddl
CREATE TABLE abc
(
    a INT,
    b INT,
    c INT,
    INDEX ab (a,b) STORING (c)
)
----
TABLE abc
 ├── a int
 ├── b int
 ├── c int
 ├── rowid int not null (hidden)
 ├── INDEX primary
 │    └── rowid int not null (hidden)
 └── INDEX ab
      ├── a int
      ├── b int
      ├── rowid int not null (hidden)
      └── c int (storing)

exec-ddl
CREATE TABLE xyz
(
    x INT,
    y INT,
    z INT,
    INDEX xy (x,y) STORING (z)
)
----
TABLE xyz
 ├── x int
 ├── y int
 ├── z int
 ├── rowid int not null (hidden)
 ├── INDEX primary
 │    └── rowid int not null (hidden)
 └── INDEX xy
      ├── x int
      ├── y int
      ├── rowid int not null (hidden)
      └── z int (storing)

# --------------------------------------------------
# Use exploretrace.
# --------------------------------------------------
exploretrace
SELECT * FROM abc, xyz WHERE a=x AND b=y
----
----
================================================================================
GenerateIndexScans
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

New expression 1 of 1:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc@ab
   │    └── columns: a:1(int) b:2(int) c:3(int)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

================================================================================
GenerateIndexScans
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

New expression 1 of 1:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   ├── scan xyz@xy
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

================================================================================
CommuteJoin
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

New expression 1 of 1:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

================================================================================
GenerateMergeJoins
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

New expression 1 of 1:
  inner-join (merge)
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── left ordering: +1,+2
   ├── right ordering: +5,+6
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc@ab
   │    ├── columns: a:1(int) b:2(int) c:3(int)
   │    └── ordering: +1,+2
   ├── scan xyz@xy
   │    ├── columns: x:5(int) y:6(int) z:7(int)
   │    └── ordering: +5,+6
   └── filters (true)

================================================================================
GenerateLookupJoins
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

New expression 1 of 1:
  inner-join (lookup xyz@xy)
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── key columns: [1 2] = [5 6]
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   └── filters (true)

================================================================================
CommuteJoin
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

No new expressions.

================================================================================
GenerateMergeJoins
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

New expression 1 of 1:
  inner-join (merge)
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── left ordering: +5,+6
   ├── right ordering: +1,+2
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan xyz@xy
   │    ├── columns: x:5(int) y:6(int) z:7(int)
   │    └── ordering: +5,+6
   ├── scan abc@ab
   │    ├── columns: a:1(int) b:2(int) c:3(int)
   │    └── ordering: +1,+2
   └── filters (true)

================================================================================
GenerateLookupJoins
================================================================================
Source expression:
  inner-join
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   ├── scan abc
   │    └── columns: a:1(int) b:2(int) c:3(int)
   └── filters
        ├── a = x [type=bool, outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
        └── b = y [type=bool, outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)]

New expression 1 of 1:
  inner-join (lookup abc@ab)
   ├── columns: a:1(int!null) b:2(int!null) c:3(int) x:5(int!null) y:6(int!null) z:7(int)
   ├── key columns: [5 6] = [1 2]
   ├── fd: (1)==(5), (5)==(1), (2)==(6), (6)==(2)
   ├── scan xyz
   │    └── columns: x:5(int) y:6(int) z:7(int)
   └── filters (true)
----
----
