code: private void addJoin(TableAlias left, Object[] leftKeys, TableAlias right, Object[] rightKeys, boolean outer,
              String name)
      {
          TableAlias extAlias, rightCopy;
  
          left.addJoin(new Join(left, leftKeys, right, rightKeys, outer, name));
  
          // build join between left and extents of right
          if (right.hasExtents())
          {
              for (int i = 0; i < right.extents.size(); i++)
              {
                  extAlias = (TableAlias) right.extents.get(i);
                  FieldDescriptor[] extKeys = getExtentFieldDescriptors(extAlias, (FieldDescriptor[]) rightKeys);
  
                  left.addJoin(new Join(left, leftKeys, extAlias, extKeys, true, name));
              }
          }
  
          // we need to copy the alias on the right for each extent on the left
          if (left.hasExtents())
          {
              for (int i = 0; i < left.extents.size(); i++)
              {
                  extAlias = (TableAlias) left.extents.get(i);
                  FieldDescriptor[] extKeys = getExtentFieldDescriptors(extAlias, (FieldDescriptor[]) leftKeys);
                  rightCopy = right.copy("C" + i);
  
                  // copies are treated like normal extents
                  right.extents.add(rightCopy);
                  right.extents.addAll(rightCopy.extents);
  
                  addJoin(extAlias, extKeys, rightCopy, rightKeys, true, name);
              }
          }
      }
docs: add a join between two aliases
  
  TODO BRJ : This needs refactoring, it looks kind of weird
  
  no extents
  A1   -> A2
  
  extents on the right
  A1   -> A2
  A1   -> A2E0
  
  extents on the left : copy alias on right, extents point to copies
  A1   -> A2
  A1E0 -> A2C0
  
  extents on the left and right
  A1   -> A2
  A1   -> A2E0
  A1E0 -> A2C0
  A1E0 -> A2E0C0
  
  @param left
  @param leftKeys
  @param right
  @param rightKeys
  @param outer
  @param name