docs: @Override
      public Node visitJoinRelation(SqlBaseParser.JoinRelationContext context)
      {
          Relation left = (Relation) visit(context.left);
          Relation right;
  
          if (context.CROSS() != null) {
              right = (Relation) visit(context.right);
              return new Join(getLocation(context), Join.Type.CROSS, left, right, Optional.empty());
          }
  
          JoinCriteria criteria;
          if (context.NATURAL() != null) {
              right = (Relation) visit(context.right);
              criteria = new NaturalJoin();
          }
          else {
              right = (Relation) visit(context.rightRelation);
              if (context.joinCriteria().ON() != null) {
                  criteria = new JoinOn((Expression) visit(context.joinCriteria().booleanExpression()));
              }
              else if (context.joinCriteria().USING() != null) {
                  criteria = new JoinUsing(visit(context.joinCriteria().identifier(), Identifier.class));
              }
              else {
                  throw new IllegalArgumentException("Unsupported join criteria");
              }
          }
  
          Join.Type joinType;
          if (context.joinType().LEFT() != null) {
              joinType = Join.Type.LEFT;
          }
          else if (context.joinType().RIGHT() != null) {
              joinType = Join.Type.RIGHT;
          }
          else if (context.joinType().FULL() != null) {
              joinType = Join.Type.FULL;
          }
          else {
              joinType = Join.Type.INNER;
          }
  
          return new Join(getLocation(context), joinType, left, right, Optional.of(criteria));
      }