Convert GeoJSON document to Sdo_Geometry objects

Andy Versal is a reader of this website.
He recently modified my SDO2GEOJSON function.
Andy supplied me with the fixes which now appear in the original article describing that function.

In return he has provided me with a copy of his function that converts GeoJSON to Sdo_Geometry.

 CREATE OR REPLACE
 FUNCTION geoJSON2SDO(p_geoJson        IN CLOB,
                      p_sdo_srid       IN NUMBER DEFAULT 8307,
                      p_decimal_places IN pls_integer DEFAULT 7,
                      p_num_fmt        IN varchar2 DEFAULT '999.99999999999999999999')
 RETURN sdo_geometry
 IS
   -- Supports only geometry.type : polygon, multipolygon with or without holes
   -- Oracle RDBMS 12c only
   l_geometry sdo_geometry;
   l_poly_ord sdo_ordinate_array := sdo_ordinate_array();
   l_info_array sdo_elem_info_array := sdo_elem_info_array();
   i pls_integer:=0;
   l_gtype varchar2(50);
   l_sdo_gtype NUMBER:=NULL;
   l_ring_num pls_integer:=0;
   l_poly_count pls_integer:=0;
   l_geom_errors varchar2(4000);
   l_ord_offset pls_integer:=0;
  BEGIN
    SELECT json_value(p_geoJson,'$.geometry.type') INTO l_gtype
    FROM dual;
    -- polygon
    IF LOWER(l_gtype)='polygon' THEN
     -- Geometry contains one polygon with or without holes
     l_sdo_gtype:=2003;
     -- ordinates
     SELECT trunc(to_number(ord,p_num_fmt),p_decimal_places) bulk collect INTO l_poly_ord
     FROM json_table(p_geoJson,'$.geometry.coordinates[*]'
           COLUMNS (nested path '$[*]'
                      COLUMNS (nested path '$[*]'
                           COLUMNS (ord VARCHAR2(100) path '$')
                              )
                   )
          )
      WHERE ord IS NOT NULL;
      IF l_poly_ord.COUNT!=0 THEN
        -- rings loop, sdo_elem_info
        FOR r IN (SELECT num1,num2,trunc(to_number(ord,p_num_fmt),p_decimal_places)
                  FROM json_table(p_geoJson,'$.geometry.coordinates[*]'
                    COLUMNS (num1 FOR ORDINALITY,nested path '$[*]'
                      COLUMNS (num2 FOR ORDINALITY, nested path '$[*]'
                           COLUMNS (ord VARCHAR2(100) path '$')
                               )
                             )
                        )
                  WHERE ord IS NOT NULL AND num2=1) loop
         i:=i+1;l_ring_num:=l_ring_num+1;
         l_info_array.extend;
         l_info_array(i):=r.num1;
         i:=i+1;
         l_info_array.extend;
         IF l_ring_num=1 THEN
          -- exterior polygon ring
          l_info_array(i):=1003;
         ELSE
          -- interior polygon ring
          l_info_array(i):=2003;
         END IF;
         i:=i+1;
         l_info_array.extend;
         l_info_array(i):=1;
        END loop;
      END IF;
    END IF;
    -- multipolygon
    IF LOWER(l_gtype)='multipolygon' THEN
     -- Geometry can have multiple, disjoint polygons (more than one exterior boundary)
     l_sdo_gtype:=2007;
     -- ordinates
     SELECT trunc(to_number(ord,p_num_fmt),p_decimal_places) bulk collect INTO l_poly_ord
     FROM json_table(p_geoJson,'$.geometry.coordinates[*]'
           COLUMNS (nested path '$[*]'
                COLUMNS (nested path '$[*]'
                      COLUMNS (nested path '$[*]'
                           COLUMNS (ord VARCHAR2(100) path '$')
                              )
                         )
                   )
          )
     WHERE ord IS NOT NULL;
     IF l_poly_ord.COUNT!=0 THEN
     -- polygons loop
      FOR p IN (SELECT *
                FROM json_table( p_geoJson,'$.geometry.coordinates[*]'
                         COLUMNS (polyords varchar2(4000) FORMAT JSON path '$') ) ) loop
        l_poly_count:=l_poly_count+1;
        -- rings loop, sdo_elem_info
        l_ring_num:=0;
        FOR r IN (SELECT num1,num2,trunc(to_number(ord,p_num_fmt),p_decimal_places)
                  FROM json_table(p.polyords,'$[*]'
                    COLUMNS (num1 FOR ORDINALITY,nested path '$[*]'
                      COLUMNS (num2 FOR ORDINALITY, nested path '$[*]'
                           COLUMNS (ord VARCHAR2(100) path '$')
                               )
                             )
                        )
                  WHERE ord IS NOT NULL AND num2=1) loop
         i:=i+1;l_ring_num:=l_ring_num+1;
         l_info_array.extend;
         l_info_array(i):=r.num1+l_ord_offset;
         i:=i+1;
         l_info_array.extend;
         IF l_ring_num=1 THEN
          -- exterior polygon ring
          l_info_array(i):=1003;
         ELSE
          -- interior polygon ring
          l_info_array(i):=2003;
         END IF;
         i:=i+1;
         l_info_array.extend;
         l_info_array(i):=1;
        END loop;
        -- ordinates offset
        SELECT COUNT(*)+l_ord_offset INTO l_ord_offset
        FROM json_table(p.polyords,'$[*]'
           COLUMNS (nested path '$[*]'
                      COLUMNS (nested path '$[*]'
                           COLUMNS (ord VARCHAR2(100) path '$')
                              )
                   )
             )
        WHERE ord IS NOT NULL;
      END loop;
      IF l_poly_count=1 THEN
        l_sdo_gtype:=2003;
      END IF;
     END IF;
    END IF;
    IF l_sdo_gtype IS NOT NULL THEN
     IF l_poly_ord.COUNT=0 THEN
       RETURN NULL;
     ELSE
      l_geometry:=sdo_geometry(l_sdo_gtype,p_sdo_srid,NULL,l_info_array,l_poly_ord);
      -- check geometry
      SELECT sdo_geom.validate_geometry_with_context(l_geometry,diminfo) INTO l_geom_errors
      FROM user_sdo_geom_metadata;
      IF l_geom_errors!='TRUE' THEN
        -- fix ora-13367 error (wrong orientation for interior/exterior rings)
        IF l_geom_errors LIKE '13367 %' THEN
         l_geometry:=sdo_util.rectify_geometry(l_geometry,0.005);
        ELSE
         raise_application_error(-20000,l_geom_errors);
        END IF;
      END IF;
      RETURN l_geometry;
     END IF;
    END IF;
 END geoJSON2SDO;

Thanks to Andy Versal for this function.