Ticket #210: postgis-nullfix.patch

File postgis-nullfix.patch, 19.8 KB (added by mcayland, 3 years ago)
  • postgis/lwgeom_geos.c

     
    107107        GEOSGeometry * geos_result=NULL; 
    108108        int SRID=-1; 
    109109        size_t offset = 0; 
     110        bits8 *bitmap; 
     111        int bitmask; 
    110112#if POSTGIS_DEBUG_LEVEL > 0 
    111113        static int call=1; 
    112114#endif 
    113115#if POSTGIS_GEOS_VERSION >= 31 
     116        int gotsrid = 0; 
    114117        int allpolys=1; 
    115118#endif 
    116119 
     
    128131 
    129132        nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); 
    130133 
     134        bitmap = ARR_NULLBITMAP(array); 
     135 
    131136        POSTGIS_DEBUGF(3, "unite_garray: number of elements: %d", nelems); 
    132137 
    133138        if ( nelems == 0 ) PG_RETURN_NULL(); 
    134139 
    135140        /* One-element union is the element itself */ 
    136         if ( nelems == 1 ) PG_RETURN_POINTER((PG_LWGEOM *)(ARR_DATA_PTR(array))); 
     141        if ( nelems == 1 ) 
     142        { 
     143                /* If the element is a NULL then we need to handle it separately */ 
     144                if (bitmap && (*bitmap & 1) == 0) 
     145                        PG_RETURN_NULL(); 
     146                else 
     147                        PG_RETURN_POINTER((PG_LWGEOM *)(ARR_DATA_PTR(array))); 
     148        } 
    137149 
    138150        /* Ok, we really need geos now ;) */ 
    139151        initGEOS(lwnotice, lwnotice); 
     
    145157        ** If they are, we can use UnionCascaded for faster results. 
    146158        */ 
    147159        offset = 0; 
     160        bitmask = 1; 
     161        gotsrid = 0; 
    148162        for ( i = 0; i < nelems; i++ ) 
    149163        { 
    150                 PG_LWGEOM *pggeom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
    151                 int pgtype = TYPE_GETTYPE(pggeom->type); 
    152                 offset += INTALIGN(VARSIZE(pggeom)); 
    153                 if ( ! i ) /* Initialize SRID */ 
     164                /* Don't do anything for NULL values */ 
     165                if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap) 
    154166                { 
    155                         SRID = pglwgeom_getSRID(pggeom); 
    156                         if ( TYPE_HASZ(pggeom->type) ) is3d = 1; 
     167                        PG_LWGEOM *pggeom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
     168                        int pgtype = TYPE_GETTYPE(pggeom->type); 
     169                        offset += INTALIGN(VARSIZE(pggeom)); 
     170                        if ( ! gotsrid ) /* Initialize SRID */ 
     171                        { 
     172                                SRID = pglwgeom_getSRID(pggeom); 
     173                                gotsrid = 1; 
     174                                if ( TYPE_HASZ(pggeom->type) ) is3d = 1; 
     175                        } 
     176                        else 
     177                        { 
     178                                errorIfSRIDMismatch(SRID, pglwgeom_getSRID(pggeom)); 
     179                        } 
     180 
     181                        if ( pgtype != POLYGONTYPE && pgtype != MULTIPOLYGONTYPE ) 
     182                        { 
     183                                allpolys = 0; 
     184                                break; 
     185                        } 
    157186                } 
    158                 if ( pgtype != POLYGONTYPE && pgtype != MULTIPOLYGONTYPE ) 
    159                 { 
    160                         allpolys = 0; 
    161                         break; 
     187 
     188                /* Advance NULL bitmap */ 
     189                if (bitmap) 
     190                { 
     191                        bitmask <<= 1; 
     192                        if (bitmask == 0x100) 
     193                        { 
     194                                bitmap++; 
     195                                bitmask = 1; 
     196                        } 
    162197                } 
    163198        } 
    164199 
     
    176211                ** First make an array of GEOS Polygons. 
    177212                */ 
    178213                offset = 0; 
     214                bitmap = ARR_NULLBITMAP(array); 
     215                bitmask = 1; 
    179216                for ( i = 0; i < nelems; i++ ) 
    180217                { 
    181                         PG_LWGEOM *pggeom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
    182                         int pgtype = TYPE_GETTYPE(pggeom->type); 
    183                         offset += INTALIGN(VARSIZE(pggeom)); 
    184                         if ( pgtype == POLYGONTYPE ) 
     218                        /* Don't do anything for NULL values */ 
     219                        if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap) 
    185220                        { 
    186                                 if ( curgeom == geoms_size ) 
     221                                PG_LWGEOM *pggeom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
     222                                int pgtype = TYPE_GETTYPE(pggeom->type); 
     223                                offset += INTALIGN(VARSIZE(pggeom)); 
     224                                if ( pgtype == POLYGONTYPE ) 
    187225                                { 
    188                                         geoms_size *= 2; 
    189                                         geoms = repalloc( geoms, sizeof(GEOSGeom) * geoms_size ); 
    190                                 } 
    191                                 geoms[curgeom] = (GEOSGeometry *)POSTGIS2GEOS(pggeom); 
    192                                 curgeom++; 
    193                         } 
    194                         if ( pgtype == MULTIPOLYGONTYPE ) 
    195                         { 
    196                                 int j = 0; 
    197                                 LWGEOM_INSPECTED *lwgeom = lwgeom_inspect(SERIALIZED_FORM(pggeom)); 
    198                                 for ( j = 0; j < lwgeom->ngeometries; j++ ) 
    199                                 { 
    200                                         LWPOLY *lwpoly = NULL; 
    201                                         int k = 0; 
    202226                                        if ( curgeom == geoms_size ) 
    203227                                        { 
    204228                                                geoms_size *= 2; 
    205229                                                geoms = repalloc( geoms, sizeof(GEOSGeom) * geoms_size ); 
    206230                                        } 
    207                                         /* This builds a LWPOLY on top of the serialized form */ 
    208                                         lwpoly = lwgeom_getpoly_inspected(lwgeom, j); 
    209                                         geoms[curgeom] = LWGEOM2GEOS(lwpoly_as_lwgeom(lwpoly)); 
    210                                         /* We delicately free the LWPOLY and POINTARRAY structs, leaving the serialized form below untouched. */ 
    211                                         for ( k = 0; k < lwpoly->nrings; k++ ) 
     231                                        geoms[curgeom] = (GEOSGeometry *)POSTGIS2GEOS(pggeom); 
     232                                        curgeom++; 
     233                                } 
     234                                if ( pgtype == MULTIPOLYGONTYPE ) 
     235                                { 
     236                                        int j = 0; 
     237                                        LWGEOM_INSPECTED *lwgeom = lwgeom_inspect(SERIALIZED_FORM(pggeom)); 
     238                                        for ( j = 0; j < lwgeom->ngeometries; j++ ) 
    212239                                        { 
    213                                                 lwfree(lwpoly->rings[k]); 
     240                                                LWPOLY *lwpoly = NULL; 
     241                                                int k = 0; 
     242                                                if ( curgeom == geoms_size ) 
     243                                                { 
     244                                                        geoms_size *= 2; 
     245                                                        geoms = repalloc( geoms, sizeof(GEOSGeom) * geoms_size ); 
     246                                                } 
     247                                                /* This builds a LWPOLY on top of the serialized form */ 
     248                                                lwpoly = lwgeom_getpoly_inspected(lwgeom, j); 
     249                                                geoms[curgeom] = LWGEOM2GEOS(lwpoly_as_lwgeom(lwpoly)); 
     250                                                /* We delicately free the LWPOLY and POINTARRAY structs, leaving the serialized form below untouched. */ 
     251                                                for ( k = 0; k < lwpoly->nrings; k++ ) 
     252                                                { 
     253                                                        lwfree(lwpoly->rings[k]); 
     254                                                } 
     255                                                lwpoly_release(lwpoly); 
     256                                                curgeom++; 
    214257                                        } 
    215                                         lwpoly_release(lwpoly); 
    216                                         curgeom++; 
    217258                                } 
    218259                        } 
    219260 
     261                        /* Advance NULL bitmap */ 
     262                        if (bitmap) 
     263                        { 
     264                                bitmask <<= 1; 
     265                                if (bitmask == 0x100) 
     266                                { 
     267                                        bitmap++; 
     268                                        bitmask = 1; 
     269                                } 
     270                        } 
    220271                } 
    221272                /* 
    222273                ** Take our GEOS Polygons and turn them into a GEOS MultiPolygon, 
    223274                ** then pass that into cascaded union. 
    224275                */ 
    225                 g1 = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, geoms, curgeom); 
    226                 if ( g1 ) g2 = GEOSUnionCascaded(g1); 
    227                 if ( g2 ) GEOSSetSRID(g2, SRID); 
    228                 if ( g2 ) result = GEOS2POSTGIS(g2, is3d); 
    229                 /* Clean up the mess. */ 
    230                 if ( g1 ) GEOSGeom_destroy((GEOSGeometry *)g1); 
    231                 if ( g2 ) GEOSGeom_destroy(g2); 
     276                if (curgeom > 0) 
     277                { 
     278                        g1 = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, geoms, curgeom); 
     279                        if ( g1 ) g2 = GEOSUnionCascaded(g1); 
     280                        if ( g2 ) GEOSSetSRID(g2, SRID); 
     281                        if ( g2 ) result = GEOS2POSTGIS(g2, is3d); 
     282                        /* Clean up the mess. */ 
     283                        if ( g1 ) GEOSGeom_destroy((GEOSGeometry *)g1); 
     284                        if ( g2 ) GEOSGeom_destroy(g2); 
     285                } 
     286                else 
     287                { 
     288                        /* All we found were NULLs, so let's return NULL */ 
     289                        PG_RETURN_NULL(); 
     290                } 
    232291        } 
    233292        else 
    234293        { 
     
    237296                ** Heterogeneous result, let's slog through this one union at a time. 
    238297                */ 
    239298                offset = 0; 
     299                bitmap = ARR_NULLBITMAP(array); 
     300                bitmask = 1; 
    240301                for (i=0; i<nelems; i++) 
    241302                { 
    242                         PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
    243                         offset += INTALIGN(VARSIZE(geom)); 
    244  
    245                         pgis_geom = geom; 
    246  
    247                         POSTGIS_DEBUGF(3, "geom %d @ %p", i, geom); 
    248  
    249                         /* Check is3d flag */ 
    250                         if ( TYPE_HASZ(geom->type) ) is3d = 1; 
    251  
    252                         /* Check SRID homogeneity and initialize geos result */ 
    253                         if ( ! i ) 
     303                        /* Don't do anything for NULL values */ 
     304                        if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap) 
    254305                        { 
    255                                 geos_result = (GEOSGeometry *)POSTGIS2GEOS(geom); 
    256                                 SRID = pglwgeom_getSRID(geom); 
    257                                 POSTGIS_DEBUGF(3, "first geom is a %s", lwgeom_typename(TYPE_GETTYPE(geom->type))); 
    258                                 continue; 
     306                                PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
     307                                offset += INTALIGN(VARSIZE(geom)); 
     308         
     309                                pgis_geom = geom; 
     310         
     311                                POSTGIS_DEBUGF(3, "geom %d @ %p", i, geom); 
     312         
     313                                /* Check is3d flag */ 
     314                                if ( TYPE_HASZ(geom->type) ) is3d = 1; 
     315         
     316                                /* Check SRID homogeneity and initialize geos result */ 
     317                                if ( ! geos_result ) 
     318                                { 
     319                                        geos_result = (GEOSGeometry *)POSTGIS2GEOS(geom); 
     320                                        SRID = pglwgeom_getSRID(geom); 
     321                                        POSTGIS_DEBUGF(3, "first geom is a %s", lwgeom_typename(TYPE_GETTYPE(geom->type))); 
     322                                } 
     323                                else 
     324                                { 
     325                                        errorIfSRIDMismatch(SRID, pglwgeom_getSRID(geom)); 
     326         
     327                                        g1 = POSTGIS2GEOS(pgis_geom); 
     328         
     329                                        POSTGIS_DEBUGF(3, "unite_garray(%d): adding geom %d to union (%s)", 
     330                                                call, i, lwgeom_typename(TYPE_GETTYPE(geom->type))); 
     331         
     332                                        g2 = GEOSUnion(g1, geos_result); 
     333                                        if ( g2 == NULL ) 
     334                                        { 
     335                                                GEOSGeom_destroy((GEOSGeometry *)g1); 
     336                                                GEOSGeom_destroy((GEOSGeometry *)geos_result); 
     337                                                elog(ERROR,"GEOS union() threw an error!"); 
     338                                        } 
     339                                        GEOSGeom_destroy((GEOSGeometry *)g1); 
     340                                        GEOSGeom_destroy((GEOSGeometry *)geos_result); 
     341                                        geos_result = g2; 
     342                                } 
    259343                        } 
    260                         else 
    261                         { 
    262                                 errorIfSRIDMismatch(SRID, pglwgeom_getSRID(geom)); 
    263                         } 
    264344 
    265                         g1 = POSTGIS2GEOS(pgis_geom); 
    266  
    267                         POSTGIS_DEBUGF(3, "unite_garray(%d): adding geom %d to union (%s)", 
    268                                        call, i, lwgeom_typename(TYPE_GETTYPE(geom->type))); 
    269  
    270                         g2 = GEOSUnion(g1, geos_result); 
    271                         if ( g2 == NULL ) 
     345                        /* Advance NULL bitmap */ 
     346                        if (bitmap) 
    272347                        { 
    273                                 GEOSGeom_destroy((GEOSGeometry *)g1); 
    274                                 GEOSGeom_destroy((GEOSGeometry *)geos_result); 
    275                                 elog(ERROR,"GEOS union() threw an error!"); 
     348                                bitmask <<= 1; 
     349                                if (bitmask == 0x100) 
     350                                { 
     351                                        bitmap++; 
     352                                        bitmask = 1; 
     353                                } 
    276354                        } 
    277                         GEOSGeom_destroy((GEOSGeometry *)g1); 
    278                         GEOSGeom_destroy((GEOSGeometry *)geos_result); 
    279                         geos_result = g2; 
     355                         
    280356                } 
    281357 
    282                 GEOSSetSRID(geos_result, SRID); 
    283                 result = GEOS2POSTGIS(geos_result, is3d); 
    284                 GEOSGeom_destroy(geos_result); 
     358                /* If geos_result is set then we found at least one non-NULL geometry */ 
     359                if (geos_result) 
     360                { 
     361                        GEOSSetSRID(geos_result, SRID); 
     362                        result = GEOS2POSTGIS(geos_result, is3d); 
     363                        GEOSGeom_destroy(geos_result); 
     364                } 
     365                else 
     366                { 
     367                        /* All we found were NULLs, so let's return NULL */ 
     368                        PG_RETURN_NULL(); 
     369                } 
    285370 
    286371#if POSTGIS_GEOS_VERSION >= 31 
    287372        } 
     
    289374 
    290375        if ( result == NULL ) 
    291376        { 
    292                 elog(ERROR, "Union returned a NULL geometry."); 
    293                 PG_RETURN_NULL(); /* never get here */ 
     377                /* Union returned a NULL geometry */ 
     378                PG_RETURN_NULL(); 
    294379        } 
    295380 
    296381        PG_RETURN_POINTER(result); 
     
    27682853        GEOSGeometry *geos_result; 
    27692854        const GEOSGeometry **vgeoms; 
    27702855        int SRID=-1; 
     2856        int cnt = 0; 
    27712857        size_t offset; 
     2858        bits8 *bitmap; 
     2859        int bitmask; 
    27722860#if POSTGIS_DEBUG_LEVEL >= 3 
    27732861        static int call=1; 
    27742862#endif 
     
    27952883 
    27962884        vgeoms = palloc(sizeof(GEOSGeometry *)*nelems); 
    27972885        offset = 0; 
     2886        cnt = 0; 
     2887        bitmap = ARR_NULLBITMAP(array); 
     2888        bitmask = 1; 
    27982889        for (i=0; i<nelems; i++) 
    27992890        { 
    2800                 PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
    2801                 offset += INTALIGN(VARSIZE(geom)); 
    2802  
    2803                 vgeoms[i] = (GEOSGeometry *)POSTGIS2GEOS(geom); 
    2804                 if ( ! i ) 
     2891                /* Don't do anything for NULL values */ 
     2892                if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap) 
    28052893                { 
    2806                         SRID = pglwgeom_getSRID(geom); 
     2894                        PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
     2895                        offset += INTALIGN(VARSIZE(geom)); 
     2896         
     2897                        vgeoms[cnt] = (GEOSGeometry *)POSTGIS2GEOS(geom); 
     2898                        if ( ! cnt ) 
     2899                        { 
     2900                                SRID = pglwgeom_getSRID(geom); 
     2901                        } 
     2902                        else 
     2903                        { 
     2904                                if ( SRID != pglwgeom_getSRID(geom) ) 
     2905                                { 
     2906                                        elog(ERROR, "polygonize: operation on mixed SRID geometries"); 
     2907                                        PG_RETURN_NULL(); 
     2908                                } 
     2909                        } 
    28072910                } 
    2808                 else 
    2809                 { 
    2810                         if ( SRID != pglwgeom_getSRID(geom) ) 
     2911 
     2912                /* Advance NULL bitmap */ 
     2913                if (bitmap) 
     2914                { 
     2915                        bitmask <<= 1; 
     2916                        if (bitmask == 0x100) 
    28112917                        { 
    2812                                 elog(ERROR, "polygonize: operation on mixed SRID geometries"); 
    2813                                 PG_RETURN_NULL(); 
     2918                                bitmap++; 
     2919                                bitmask = 1; 
    28142920                        } 
    28152921                } 
    28162922        } 
    28172923 
    28182924        POSTGIS_DEBUG(3, "polygonize_garray: invoking GEOSpolygonize"); 
    28192925 
    2820         geos_result = GEOSPolygonize(vgeoms, nelems); 
     2926        geos_result = GEOSPolygonize(vgeoms, cnt); 
    28212927 
    28222928        POSTGIS_DEBUG(3, "polygonize_garray: GEOSpolygonize returned"); 
    28232929 
    2824         for (i=0; i<nelems; ++i) GEOSGeom_destroy((GEOSGeometry *)vgeoms[i]); 
     2930        for (i=0; i<cnt; ++i) GEOSGeom_destroy((GEOSGeometry *)vgeoms[i]); 
    28252931        pfree(vgeoms); 
    28262932 
    28272933        if ( ! geos_result ) PG_RETURN_NULL(); 
  • postgis/lwgeom_functions_basic.c

     
    19481948        unsigned int outtype; 
    19491949        int i; 
    19501950        int SRID=-1; 
     1951        int cnt = 0; 
    19511952        size_t offset; 
    19521953        BOX2DFLOAT4 *box=NULL; 
     1954        bits8 *bitmap; 
     1955        int bitmask; 
    19531956 
    19541957        POSTGIS_DEBUG(2, "LWGEOM_collect_garray called."); 
    19551958 
     
    19891992        lwgeoms = palloc(sizeof(LWGEOM *)*nelems); 
    19901993        outtype = 0; 
    19911994        offset = 0; 
     1995        cnt = 0; 
     1996        bitmap = ARR_NULLBITMAP(array); 
     1997        bitmask = 1; 
     1998 
    19921999        for (i=0; i<nelems; i++) 
    19932000        { 
    1994                 PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
    1995                 unsigned int intype = TYPE_GETTYPE(geom->type); 
    1996  
    1997                 offset += INTALIGN(VARSIZE(geom)); 
    1998  
    1999                 lwgeoms[i] = lwgeom_deserialize(SERIALIZED_FORM(geom)); 
    2000  
    2001                 POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: geom %d deserialized", i); 
    2002  
    2003                 if ( ! i ) 
     2001                /* Don't do anything for NULL values */ 
     2002                if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap) 
    20042003                { 
    2005                         /* Get first geometry SRID */ 
    2006                         SRID = lwgeoms[i]->SRID; 
    2007  
    2008                         /* COMPUTE_BBOX WHEN_SIMPLE */ 
    2009                         if ( lwgeoms[i]->bbox ) 
     2004                        PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
     2005                        unsigned int intype = TYPE_GETTYPE(geom->type); 
     2006         
     2007                        offset += INTALIGN(VARSIZE(geom)); 
     2008         
     2009                        lwgeoms[cnt] = lwgeom_deserialize(SERIALIZED_FORM(geom)); 
     2010         
     2011                        POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: geom %d deserialized", i); 
     2012         
     2013                        if ( ! cnt ) 
    20102014                        { 
    2011                                 box = box2d_clone(lwgeoms[i]->bbox); 
     2015                                /* Get first geometry SRID */ 
     2016                                SRID = lwgeoms[cnt]->SRID; 
     2017         
     2018                                /* COMPUTE_BBOX WHEN_SIMPLE */ 
     2019                                if ( lwgeoms[cnt]->bbox ) 
     2020                                { 
     2021                                        box = box2d_clone(lwgeoms[cnt]->bbox); 
     2022                                } 
    20122023                        } 
    2013                 } 
    2014                 else 
    2015                 { 
    2016                         /* Check SRID homogeneity */ 
    2017                         if ( lwgeoms[i]->SRID != SRID ) 
     2024                        else 
    20182025                        { 
    2019                                 elog(ERROR, 
    2020                                      "Operation on mixed SRID geometries"); 
    2021                                 PG_RETURN_NULL(); 
    2022                         } 
    2023  
    2024                         /* COMPUTE_BBOX WHEN_SIMPLE */ 
    2025                         if ( box ) 
    2026                         { 
    2027                                 if ( lwgeoms[i]->bbox ) 
     2026                                /* Check SRID homogeneity */ 
     2027                                if ( lwgeoms[cnt]->SRID != SRID ) 
    20282028                                { 
    2029                                         box->xmin = LW_MIN(box->xmin, lwgeoms[i]->bbox->xmin); 
    2030                                         box->ymin = LW_MIN(box->ymin, lwgeoms[i]->bbox->ymin); 
    2031                                         box->xmax = LW_MAX(box->xmax, lwgeoms[i]->bbox->xmax); 
    2032                                         box->ymax = LW_MAX(box->ymax, lwgeoms[i]->bbox->ymax); 
     2029                                        elog(ERROR, 
     2030                                        "Operation on mixed SRID geometries"); 
     2031                                        PG_RETURN_NULL(); 
    20332032                                } 
    2034                                 else 
     2033         
     2034                                /* COMPUTE_BBOX WHEN_SIMPLE */ 
     2035                                if ( box ) 
    20352036                                { 
    2036                                         pfree(box); 
    2037                                         box = NULL; 
     2037                                        if ( lwgeoms[cnt]->bbox ) 
     2038                                        { 
     2039                                                box->xmin = LW_MIN(box->xmin, lwgeoms[cnt]->bbox->xmin); 
     2040                                                box->ymin = LW_MIN(box->ymin, lwgeoms[cnt]->bbox->ymin); 
     2041                                                box->xmax = LW_MAX(box->xmax, lwgeoms[cnt]->bbox->xmax); 
     2042                                                box->ymax = LW_MAX(box->ymax, lwgeoms[cnt]->bbox->ymax); 
     2043                                        } 
     2044                                        else 
     2045                                        { 
     2046                                                pfree(box); 
     2047                                                box = NULL; 
     2048                                        } 
    20382049                                } 
    20392050                        } 
    2040                 } 
    20412051 
     2052                        lwgeom_dropSRID(lwgeoms[cnt]); 
     2053                        lwgeom_drop_bbox(lwgeoms[cnt]); 
     2054         
     2055                        /* Output type not initialized */ 
     2056                        if ( ! outtype ) 
     2057                        { 
     2058                                /* Input is single, make multi */ 
     2059                                if ( intype < 4 ) outtype = intype+3; 
     2060                                /* Input is multi, make collection */ 
     2061                                else outtype = COLLECTIONTYPE; 
     2062                        } 
     2063         
     2064                        /* Input type not compatible with output */ 
     2065                        /* make output type a collection */ 
     2066                        else if ( outtype != COLLECTIONTYPE && intype != outtype-3 ) 
     2067                        { 
     2068                                outtype = COLLECTIONTYPE; 
     2069                        } 
    20422070 
    2043                 lwgeom_dropSRID(lwgeoms[i]); 
    2044                 lwgeom_drop_bbox(lwgeoms[i]); 
    2045  
    2046                 /* Output type not initialized */ 
    2047                 if ( ! outtype ) 
    2048                 { 
    2049                         /* Input is single, make multi */ 
    2050                         if ( intype < 4 ) outtype = intype+3; 
    2051                         /* Input is multi, make collection */ 
    2052                         else outtype = COLLECTIONTYPE; 
     2071                        /* Keep a count of the number of collection elements (no NULLs) */ 
     2072                        cnt++; 
    20532073                } 
    20542074 
    2055                 /* Input type not compatible with output */ 
    2056                 /* make output type a collection */ 
    2057                 else if ( outtype != COLLECTIONTYPE && intype != outtype-3 ) 
    2058                 { 
    2059                         outtype = COLLECTIONTYPE; 
     2075                /* Advance NULL bitmap */ 
     2076                if (bitmap) 
     2077                { 
     2078                        bitmask <<= 1; 
     2079                        if (bitmask == 0x100) 
     2080                        { 
     2081                                bitmap++; 
     2082                                bitmask = 1; 
     2083                        } 
    20602084                } 
    2061  
    20622085        } 
    20632086 
     2087        /* If we didn't find a non-NULL geometry, simply return NULL */ 
     2088        if ( ! cnt ) 
     2089                PG_RETURN_NULL(); 
     2090 
    20642091        POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: outtype = %d", outtype); 
    20652092 
    20662093        outlwg = (LWGEOM *)lwcollection_construct( 
    20672094                     outtype, SRID, 
    2068                      box, nelems, lwgeoms); 
     2095                     box, cnt, lwgeoms); 
    20692096 
    20702097        result = pglwgeom_serialize(outlwg); 
    20712098 
     
    21292156        int i; 
    21302157        size_t offset; 
    21312158        int SRID=-1; 
     2159        bits8 *bitmap; 
     2160        int bitmask; 
    21322161 
    21332162        POSTGIS_DEBUG(2, "LWGEOM_makeline_garray called."); 
    21342163 
     
    21692198        lwpoints = palloc(sizeof(LWGEOM *)*nelems); 
    21702199        npoints = 0; 
    21712200        offset = 0; 
     2201        bitmap = ARR_NULLBITMAP(array); 
     2202        bitmask = 1; 
    21722203        for (i=0; i<nelems; i++) 
    21732204        { 
    2174                 PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
    2175                 offset += INTALIGN(VARSIZE(geom)); 
    2176  
    2177                 if ( TYPE_GETTYPE(geom->type) != POINTTYPE ) continue; 
    2178  
    2179                 lwpoints[npoints++] = 
    2180                     lwpoint_deserialize(SERIALIZED_FORM(geom)); 
    2181  
    2182                 /* Check SRID homogeneity */ 
    2183                 if ( npoints == 1 ) 
     2205                /* Don't do anything for NULL values */ 
     2206                if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap) 
    21842207                { 
    2185                         /* Get first geometry SRID */ 
    2186                         SRID = lwpoints[npoints-1]->SRID; 
     2208                        PG_LWGEOM *geom = (PG_LWGEOM *)(ARR_DATA_PTR(array)+offset); 
     2209                        offset += INTALIGN(VARSIZE(geom)); 
     2210         
     2211                        if ( TYPE_GETTYPE(geom->type) != POINTTYPE ) continue; 
     2212         
     2213                        lwpoints[npoints++] = 
     2214                        lwpoint_deserialize(SERIALIZED_FORM(geom)); 
     2215         
     2216                        /* Check SRID homogeneity */ 
     2217                        if ( npoints == 1 ) 
     2218                        { 
     2219                                /* Get first geometry SRID */ 
     2220                                SRID = lwpoints[npoints-1]->SRID; 
     2221                        } 
     2222                        else 
     2223                        { 
     2224                                if ( lwpoints[npoints-1]->SRID != SRID ) 
     2225                                { 
     2226                                        elog(ERROR, 
     2227                                        "Operation on mixed SRID geometries"); 
     2228                                        PG_RETURN_NULL(); 
     2229                                } 
     2230                        } 
     2231         
     2232                        POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: element %d deserialized", 
     2233                                i); 
    21872234                } 
    2188                 else 
    2189                 { 
    2190                         if ( lwpoints[npoints-1]->SRID != SRID ) 
     2235 
     2236                /* Advance NULL bitmap */ 
     2237                if (bitmap) 
     2238                { 
     2239                        bitmask <<= 1; 
     2240                        if (bitmask == 0x100) 
    21912241                        { 
    2192                                 elog(ERROR, 
    2193                                      "Operation on mixed SRID geometries"); 
    2194                                 PG_RETURN_NULL(); 
     2242                                bitmap++; 
     2243                                bitmask = 1; 
    21952244                        } 
    21962245                } 
    2197  
    2198                 POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: element %d deserialized", 
    2199                                i); 
    22002246        } 
    22012247 
    22022248        /* Return null on 0-points input array */ 
  • postgis/lwgeom_accum.c

     
    2121#include "lwgeom_pg.h" 
    2222 
    2323/* Local prototypes */ 
     24Datum PGISDirectFunctionCall1(PGFunction func, Datum arg1); 
    2425Datum pgis_geometry_accum_transfn(PG_FUNCTION_ARGS); 
    2526Datum pgis_geometry_accum_finalfn(PG_FUNCTION_ARGS); 
    2627Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS); 
     
    210211        p = (pgis_abs*) PG_GETARG_POINTER(0); 
    211212 
    212213        geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); 
    213         result = DirectFunctionCall1( pgis_union_geometry_array, geometry_array ); 
     214        result = PGISDirectFunctionCall1( pgis_union_geometry_array, geometry_array ); 
     215        if (!result) 
     216                PG_RETURN_NULL(); 
    214217 
    215218        PG_RETURN_DATUM(result); 
    216219} 
     
    233236        p = (pgis_abs*) PG_GETARG_POINTER(0); 
    234237 
    235238        geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); 
    236         result = DirectFunctionCall1( LWGEOM_collect_garray, geometry_array ); 
     239        result = PGISDirectFunctionCall1( LWGEOM_collect_garray, geometry_array ); 
     240        if (!result) 
     241                PG_RETURN_NULL(); 
    237242 
    238243        PG_RETURN_DATUM(result); 
    239244} 
     
    256261        p = (pgis_abs*) PG_GETARG_POINTER(0); 
    257262 
    258263        geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); 
    259         result = DirectFunctionCall1( polygonize_garray, geometry_array ); 
     264        result = PGISDirectFunctionCall1( polygonize_garray, geometry_array ); 
     265        if (!result) 
     266                PG_RETURN_NULL(); 
    260267 
    261268        PG_RETURN_DATUM(result); 
    262269} 
     
    279286        p = (pgis_abs*) PG_GETARG_POINTER(0); 
    280287 
    281288        geometry_array = pgis_accum_finalfn(p, CurrentMemoryContext, fcinfo); 
    282         result = DirectFunctionCall1( LWGEOM_makeline_garray, geometry_array ); 
     289        result = PGISDirectFunctionCall1( LWGEOM_makeline_garray, geometry_array ); 
     290        if (!result) 
     291                PG_RETURN_NULL(); 
    283292 
    284293        PG_RETURN_DATUM(result); 
    285294} 
    286295 
     296/** 
     297* A modified version of PostgreSQL's DirectFunctionCall1 which allows NULL results; this 
     298* is required for aggregates that return NULL. 
     299*/ 
     300Datum 
     301PGISDirectFunctionCall1(PGFunction func, Datum arg1) 
     302{ 
     303        FunctionCallInfoData fcinfo; 
     304        Datum           result; 
     305 
     306        InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL); 
     307 
     308        fcinfo.arg[0] = arg1; 
     309        fcinfo.argnull[0] = false; 
     310 
     311        result = (*func) (&fcinfo); 
     312 
     313        /* Check for null result, returning a "NULL" Datum if indicated */ 
     314        if (fcinfo.isnull) 
     315                return (Datum) 0; 
     316 
     317        return result; 
     318}