Another approach to ST_Buffer would be to subdivide the geometries before buffering, and put them all together at the end. ST_SubDivide can do this for us. We can tell it how may vertices we want in each geometry (minimum of 8). Since _ST_BestSRID will try UTM first, we’ll add enough nodes to ensure we always have 8 nodes within the 1,000,000 meter width of a UTM zone by segmentizing at 62,500 meters.
CREATE OR REPLACE FUNCTION ST_Buffer(g1 geography, radius_of_buffer float, num_seg_quarter_circle integer) RETURNS geography AS $BODY$ WITH subdivided AS ( SELECT CASE WHEN ST_GeometryType(g1::geometry) = 'ST_Point' THEN g1 ELSE (SELECT ST_SubDivide(ST_Segmentize(g1::geometry, 62500), 8) AS geom) END ), transformed_local AS ( SELECT ST_Transform(g1::geometry, _ST_BestSRID(geom)) AS geom FROM subdivided ), buffered AS ( SELECT ST_Buffer(geom, radius_of_buffer, num_seg_quarter_circle) AS geom FROM transformed_local ), transformed_4326 AS ( SELECT (ST_Dump(ST_Transform(geom, 4326))).geom AS geom FROM buffered ), checksrid AS ( SELECT geom FROM transformed_4326 ) SELECT ST_Union(geom)::geography FROM checksrid; $BODY$ LANGUAGE sql VOLATILE;
Aaand, a somewhat unrelated image (just the buffered subdivision of a buffered point, not really an output from our function above. More on all this later.