LCOV - code coverage report
Current view: top level - geom/monetdb5 - geomBulk.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 497 1208 41.1 %
Date: 2024-04-25 20:03:45 Functions: 33 53 62.3 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * Foteini Alvanaki
      15             :  */
      16             : 
      17             : #include "geom.h"
      18             : #include "geod.h"
      19             : #include "geom_atoms.h"
      20             : 
      21             : /********** Geo Update Start **********/
      22             : #ifdef HAVE_RTREE
      23             : static str
      24             : filterSelectRTree(bat* outid, const bat *bid , const bat *sid, GEOSGeom const_geom, mbr *const_mbr, double distance, bit anti, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *, double), const char *name)
      25             : {
      26             :         BAT *out = NULL, *b = NULL, *s = NULL;
      27             :         BATiter b_iter;
      28             :         struct canditer ci;
      29             :         GEOSGeom col_geom;
      30             : 
      31             :         //Get BAT, BATiter and candidate list
      32             :         if ((b = BATdescriptor(*bid)) == NULL)
      33             :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
      34             :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
      35             :                 BBPunfix(b->batCacheid);
      36             :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
      37             :         }
      38             :         canditer_init(&ci, b, s);
      39             :         b_iter = bat_iterator(b);
      40             : 
      41             :         //Result BAT
      42             :         if ((out = COLnew(0, ATOMindex("oid"), ci.ncand, TRANSIENT)) == NULL) {
      43             :                 BBPunfix(b->batCacheid);
      44             :                 if (s)
      45             :                         BBPunfix(s->batCacheid);
      46             :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
      47             :         }
      48             : 
      49             :         //Get a candidate list from searching on the rtree with the constant mbr
      50             :         BUN* results_rtree = RTREEsearch(b,(mbr_t*)const_mbr, b->batCount);
      51             :         if (results_rtree == NULL) {
      52             :                 BBPunfix(b->batCacheid);
      53             :                 if (s)
      54             :                         BBPunfix(s->batCacheid);
      55             :                 BBPreclaim(out);
      56             :                 throw(MAL, name, "RTreesearch failed, returned NULL candidates");
      57             :         }
      58             : 
      59             :         //Cycle through rtree candidates
      60             :         //If there is a original candidate list, make sure the rtree cand is in there
      61             :         //Then do the actual calculation for the predicate using the GEOS function
      62             :         for (int i = 0; results_rtree[i] != BUN_NONE && i < (int) b->batCount; i++) {
      63             :                 oid cand = results_rtree[i];
      64             :                 //If we have a candidate list that is not dense, we need to check if the rtree candidate is also on the original candidate list
      65             :                 if (ci.tpe != cand_dense) {
      66             :                         //If the original candidate list does not contain the rtree cand, move on to next one
      67             :                         if (!canditer_contains(&ci,cand))
      68             :                                 continue;
      69             :                 }
      70             :                 const wkb *col_wkb = BUNtvar(b_iter, cand - b->hseqbase);
      71             :                 if ((col_geom = wkb2geos(col_wkb)) == NULL)
      72             :                         throw(MAL, name, SQLSTATE(38000) "WKB2Geos operation failed");
      73             :                 if (GEOSGetSRID_r(geoshandle, col_geom) != GEOSGetSRID_r(geoshandle, const_geom)) {
      74             :                         GEOSGeom_destroy_r(geoshandle, col_geom);
      75             :                         GEOSGeom_destroy_r(geoshandle, const_geom);
      76             :                         bat_iterator_end(&b_iter);
      77             :                         BBPunfix(b->batCacheid);
      78             :                         if (s)
      79             :                                 BBPunfix(s->batCacheid);
      80             :                         BBPreclaim(out);
      81             :                         throw(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
      82             :                 }
      83             :                 //GEOS function returns 1 on true, 0 on false and 2 on exception
      84             :                 bit cond = ((*func)(geoshandle, col_geom, const_geom, distance) == 1);
      85             :                 if (cond != anti) {
      86             :                         if (BUNappend(out, (oid*) &cand, false) != GDK_SUCCEED) {
      87             :                                 GEOSGeom_destroy_r(geoshandle, col_geom);
      88             :                                 GEOSGeom_destroy_r(geoshandle, const_geom);
      89             :                                 bat_iterator_end(&b_iter);
      90             :                                 BBPunfix(b->batCacheid);
      91             :                                 if (s)
      92             :                                         BBPunfix(s->batCacheid);
      93             :                                 BBPreclaim(out);
      94             :                                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
      95             :                         }
      96             :                 }
      97             :                 GEOSGeom_destroy_r(geoshandle, col_geom);
      98             :         }
      99             :         GEOSGeom_destroy_r(geoshandle, const_geom);
     100             :         bat_iterator_end(&b_iter);
     101             :         BBPunfix(b->batCacheid);
     102             :         if (s)
     103             :                 BBPunfix(s->batCacheid);
     104             :         *outid = out->batCacheid;
     105             :         BBPkeepref(out);
     106             :         return MAL_SUCCEED;
     107             : }
     108             : #endif
     109             : 
     110             : static str
     111           0 : filterSelectNoIndex(bat* outid, const bat *bid , const bat *sid, wkb *wkb_const, double distance, bit anti, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *, double), const char *name)
     112             : {
     113           0 :         BAT *out = NULL, *b = NULL, *s = NULL;
     114           0 :         BATiter b_iter;
     115           0 :         struct canditer ci;
     116           0 :         GEOSGeom col_geom, const_geom;
     117             : 
     118             :         //WKB constant is NULL
     119           0 :         if ((const_geom = wkb2geos(wkb_const)) == NULL) {
     120           0 :                 if ((out = BATdense(0, 0, 0)) == NULL)
     121           0 :                         throw(MAL, name, GDK_EXCEPTION);
     122           0 :                 *outid = out->batCacheid;
     123           0 :                 BBPkeepref(out);
     124           0 :                 return MAL_SUCCEED;
     125             :         }
     126             : 
     127             :         //Get BAT, BATiter and candidate list
     128           0 :         if ((b = BATdescriptor(*bid)) == NULL)
     129           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     130           0 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     131           0 :                 BBPunfix(b->batCacheid);
     132           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     133             :         }
     134           0 :         canditer_init(&ci, b, s);
     135           0 :         b_iter = bat_iterator(b);
     136             : 
     137             :         //Result BAT
     138           0 :         if ((out = COLnew(0, ATOMindex("oid"), ci.ncand, TRANSIENT)) == NULL) {
     139           0 :                 BBPunfix(b->batCacheid);
     140           0 :                 if (s)
     141           0 :                         BBPunfix(s->batCacheid);
     142           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     143             :         }
     144             : 
     145           0 :         for (BUN i = 0; i < ci.ncand; i++) {
     146           0 :                 BUN cand = canditer_next(&ci);
     147           0 :                 const wkb *col_wkb = BUNtvar(b_iter, cand - b->hseqbase);
     148           0 :                 if ((col_geom = wkb2geos(col_wkb)) == NULL)
     149           0 :                         throw(MAL, name, SQLSTATE(38000) "WKB2Geos operation failed");
     150           0 :                 if (GEOSGetSRID_r(geoshandle, col_geom) != GEOSGetSRID_r(geoshandle, const_geom)) {
     151           0 :                         GEOSGeom_destroy_r(geoshandle, col_geom);
     152           0 :                         GEOSGeom_destroy_r(geoshandle, const_geom);
     153           0 :                         bat_iterator_end(&b_iter);
     154           0 :                         BBPunfix(b->batCacheid);
     155           0 :                         if (s)
     156           0 :                                 BBPunfix(s->batCacheid);
     157           0 :                         BBPreclaim(out);
     158           0 :                         throw(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
     159             :                 }
     160             :                 //GEOS function returns 1 on true, 0 on false and 2 on exception
     161           0 :                 bit cond = ((*func)(geoshandle, col_geom, const_geom, distance) == 1);
     162           0 :                 if (cond != anti) {
     163           0 :                         if (BUNappend(out, (oid*) &cand, false) != GDK_SUCCEED) {
     164           0 :                                 if (col_geom)
     165           0 :                                         GEOSGeom_destroy_r(geoshandle, col_geom);
     166           0 :                                 if (const_geom)
     167           0 :                                         GEOSGeom_destroy_r(geoshandle, const_geom);
     168           0 :                                 bat_iterator_end(&b_iter);
     169           0 :                                 BBPunfix(b->batCacheid);
     170           0 :                                 if (s)
     171           0 :                                         BBPunfix(s->batCacheid);
     172           0 :                                 BBPreclaim(out);
     173           0 :                                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     174             :                         }
     175             :                 }
     176           0 :                 GEOSGeom_destroy_r(geoshandle, col_geom);
     177             :         }
     178             : 
     179           0 :         GEOSGeom_destroy_r(geoshandle, const_geom);
     180           0 :         bat_iterator_end(&b_iter);
     181           0 :         BBPunfix(b->batCacheid);
     182           0 :         if (s)
     183           0 :                 BBPunfix(s->batCacheid);
     184           0 :         *outid = out->batCacheid;
     185           0 :         BBPkeepref(out);
     186           0 :         return MAL_SUCCEED;
     187             : }
     188             : 
     189             : str
     190           0 : wkbIntersectsSelectRTree(bat* outid, const bat *bid , const bat *sid, wkb **wkb_const, bit *anti) {
     191             : #ifdef HAVE_RTREE
     192             :         //If there is an RTree on memory or on file, use the RTree method. Otherwise, use the no index version.
     193             :         if (RTREEexists_bid((bat*)bid)) {
     194             :                 //Calculate MBR of constant geometry first
     195             :                 GEOSGeom const_geom;
     196             :                 if ((const_geom = wkb2geos(*wkb_const)) == NULL) {
     197             :                         BAT *out = NULL;
     198             :                         if ((out = BATdense(0, 0, 0)) == NULL)
     199             :                                 throw(MAL, "geom.wkbIntersectsSelectRTree", GDK_EXCEPTION);
     200             :                         *outid = out->batCacheid;
     201             :                         BBPkeepref(out);
     202             :                         return MAL_SUCCEED;
     203             :                 }
     204             :                 //Calculate the MBR for the constant geometry
     205             :                 mbr *const_mbr = NULL;
     206             :                 wkbMBR(&const_mbr,wkb_const);
     207             : 
     208             :                 return filterSelectRTree(outid,bid,sid,const_geom,const_mbr,0,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsSelectRTree");
     209             :         }
     210             :         else
     211             :                 return filterSelectNoIndex(outid,bid,sid,*wkb_const,0,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsSelectNoIndex");
     212             : #else
     213           0 :         return filterSelectNoIndex(outid,bid,sid,*wkb_const,0,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsSelectNoIndex");
     214             : #endif
     215             : }
     216             : 
     217             : str
     218           0 : wkbDWithinSelectRTree(bat* outid, const bat *bid , const bat *sid, wkb **wkb_const, dbl* distance, bit *anti) {
     219             : #ifdef HAVE_RTREE
     220             :         //If there is an RTree on memory or on file, use the RTree method. Otherwise, use the no index version.
     221             :         if (RTREEexists_bid((bat*)bid)) {
     222             :                 //Calculate MBR of constant geometry first
     223             :                 GEOSGeom const_geom;
     224             :                 if ((const_geom = wkb2geos(*wkb_const)) == NULL) {
     225             :                         BAT *out = NULL;
     226             :                         if ((out = BATdense(0, 0, 0)) == NULL)
     227             :                                 throw(MAL, "geom.wkbDWithinSelectRTree", GDK_EXCEPTION);
     228             :                         *outid = out->batCacheid;
     229             :                         BBPkeepref(out);
     230             :                         return MAL_SUCCEED;
     231             :                 }
     232             :                 //Calculate the MBR for the constant geometry
     233             :                 mbr *const_mbr = NULL;
     234             :                 wkbMBR(&const_mbr,wkb_const);
     235             : 
     236             :                 //We expand the bounding box to cover the "distance within" area
     237             :                 //And use GEOSIntersects with the expanded bounding box
     238             :                 //This expands the box too much
     239             :                 //But better to get more false candidates than not getting a true candidate
     240             :                 const_mbr->xmin -=(*distance);
     241             :                 const_mbr->ymin -=(*distance);
     242             :                 const_mbr->xmax +=(*distance);
     243             :                 const_mbr->ymax +=(*distance);
     244             : 
     245             :                 return filterSelectRTree(outid,bid,sid,const_geom,const_mbr,*distance,*anti,GEOSDistanceWithin_r,"geom.wkbDWithinSelectRTree");
     246             :         }
     247             :         else
     248             :                 return filterSelectNoIndex(outid,bid,sid,*wkb_const,*distance,*anti,GEOSDistanceWithin_r,"geom.wkbDWithinSelectNoIndex");
     249             : #else
     250           0 :         return filterSelectNoIndex(outid,bid,sid,*wkb_const,*distance,*anti,GEOSDistanceWithin_r,"geom.wkbDWithinSelectNoIndex");
     251             : #endif
     252             : }
     253             : 
     254             : str
     255           0 : wkbIntersectsSelectNoIndex(bat* outid, const bat *bid , const bat *sid, wkb **wkb_const, bit *anti) {
     256           0 :         return filterSelectNoIndex(outid,bid,sid,*wkb_const,0,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsSelectNoIndex");
     257             : }
     258             : 
     259             : str
     260           0 : wkbDWithinSelectNoIndex(bat* outid, const bat *bid , const bat *sid, wkb **wkb_const, double *distance, bit *anti) {
     261           0 :         return filterSelectNoIndex(outid,bid,sid,*wkb_const,*distance,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsSelectNoIndex");
     262             : }
     263             : 
     264             : static str
     265           0 : filterJoinNoIndex(bat *lres_id, bat *rres_id, const bat *l_id, const bat *r_id, double double_flag, const bat *ls_id, const bat *rs_id, bit nil_matches, lng estimate, bit anti, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *, double), const char *name)
     266             : {
     267           0 :         BAT *lres = NULL, *rres = NULL, *l = NULL, *r = NULL, *ls = NULL, *rs = NULL;
     268           0 :         BUN estimate_safe;
     269           0 :         BATiter l_iter, r_iter;
     270           0 :         str msg = MAL_SUCCEED;
     271           0 :         struct canditer l_ci, r_ci;
     272           0 :         GEOSGeom l_geom, r_geom;
     273           0 :         GEOSGeom *l_geoms = NULL, *r_geoms = NULL;
     274             : 
     275             :         //get the input BATs
     276           0 :         if ((l = BATdescriptor(*l_id)) == NULL || (r = BATdescriptor(*r_id)) == NULL) {
     277           0 :                 if (l)
     278           0 :                         BBPunfix(l->batCacheid);
     279           0 :                 if (r)
     280             :                         BBPunfix(r->batCacheid);
     281           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     282             :         }
     283             :         //get the candidate lists
     284           0 :         if (ls_id && !is_bat_nil(*ls_id) && (ls = BATdescriptor(*ls_id)) == NULL && rs_id && !is_bat_nil(*rs_id) && (rs = BATdescriptor(*rs_id)) == NULL) {
     285           0 :                 msg = createException(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     286           0 :                 goto free;
     287             :         }
     288           0 :         canditer_init(&l_ci, l, ls);
     289           0 :         canditer_init(&r_ci, r, rs);
     290             : 
     291             :         // properly handle the estimate
     292           0 :         if (is_lng_nil(estimate) || estimate == 0) {
     293           0 :                 if (l_ci.ncand > r_ci.ncand)
     294           0 :                         estimate = l_ci.ncand;
     295             :                 else
     296           0 :                         estimate = r_ci.ncand;
     297             :         }
     298             : 
     299           0 :         if (estimate < 0 || is_lng_nil(estimate) || estimate > (lng) BUN_MAX)
     300             :                 estimate_safe = BUN_NONE;
     301             :         else
     302             :                 estimate_safe = (BUN) estimate;
     303             : 
     304             :         // create new BATs for the output
     305           0 :         if ((lres = COLnew(0, ATOMindex("oid"), estimate_safe, TRANSIENT)) == NULL) {
     306           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     307           0 :                 goto free;
     308             :         }
     309           0 :         if ((rres = COLnew(0, ATOMindex("oid"), estimate_safe, TRANSIENT)) == NULL) {
     310           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     311           0 :                 goto free;
     312             :         }
     313             : 
     314             :         //Allocate arrays for reutilizing GEOS type conversion
     315           0 :         if ((l_geoms = GDKmalloc(l_ci.ncand * sizeof(GEOSGeometry *))) == NULL || (r_geoms = GDKmalloc(r_ci.ncand * sizeof(GEOSGeometry *))) == NULL) {
     316           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     317           0 :                 goto free;
     318             :         }
     319             : 
     320           0 :         l_iter = bat_iterator(l);
     321           0 :         r_iter = bat_iterator(r);
     322             : 
     323             :         //Convert wkb to GEOS only once
     324           0 :         for (BUN i = 0; i < l_ci.ncand; i++) {
     325           0 :                 oid l_oid = canditer_next(&l_ci);
     326           0 :                 l_geoms[i] = wkb2geos((const wkb*) BUNtvar(l_iter, l_oid - l->hseqbase));
     327             :         }
     328           0 :         for (BUN j = 0; j < r_ci.ncand; j++) {
     329           0 :                 oid r_oid = canditer_next(&r_ci);
     330           0 :                 r_geoms[j] = wkb2geos((const wkb*)BUNtvar(r_iter, r_oid - r->hseqbase));
     331             :         }
     332             : 
     333           0 :         canditer_reset(&l_ci);
     334           0 :         for (BUN i = 0; i < l_ci.ncand; i++) {
     335           0 :                 oid l_oid = canditer_next(&l_ci);
     336           0 :                 l_geom = l_geoms[i];
     337           0 :                 if (!nil_matches && l_geom == NULL)
     338           0 :                         continue;
     339           0 :                 canditer_reset(&r_ci);
     340           0 :                 for (BUN j = 0; j < r_ci.ncand; j++) {
     341           0 :                         oid r_oid = canditer_next(&r_ci);
     342           0 :                         r_geom = r_geoms[j];
     343             :                         //Null handling
     344           0 :                         if (r_geom == NULL) {
     345           0 :                                 if (nil_matches && l_geom == NULL) {
     346           0 :                                         if (BUNappend(lres, &l_oid, false) != GDK_SUCCEED || BUNappend(rres, &r_oid, false) != GDK_SUCCEED) {
     347           0 :                                                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     348           0 :                                                 bat_iterator_end(&l_iter);
     349           0 :                                                 bat_iterator_end(&r_iter);
     350           0 :                                                 goto free;
     351             :                                         }
     352             :                                 }
     353             :                                 else
     354           0 :                                         continue;
     355             :                         }
     356           0 :                         if (GEOSGetSRID_r(geoshandle, l_geom) != GEOSGetSRID_r(geoshandle, r_geom)) {
     357           0 :                                 msg = createException(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
     358           0 :                                 bat_iterator_end(&l_iter);
     359           0 :                                 bat_iterator_end(&r_iter);
     360           0 :                                 goto free;
     361             :                         }
     362             :                         //Apply the (Geom, Geom, double) -> bit function
     363           0 :                         bit cond = (*func)(geoshandle, l_geom, r_geom, double_flag) == 1;
     364           0 :                         if (cond != anti) {
     365           0 :                                 if (BUNappend(lres, &l_oid, false) != GDK_SUCCEED || BUNappend(rres, &r_oid, false) != GDK_SUCCEED) {
     366           0 :                                         msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     367           0 :                                         bat_iterator_end(&l_iter);
     368           0 :                                         bat_iterator_end(&r_iter);
     369           0 :                                         goto free;
     370             :                                 }
     371             :                         }
     372             :                 }
     373             :         }
     374             :         if (l_geoms) {
     375           0 :                 for (BUN i = 0; i < l_ci.ncand; i++) {
     376           0 :                         GEOSGeom_destroy_r(geoshandle, l_geoms[i]);
     377             :                 }
     378           0 :                 GDKfree(l_geoms);
     379             :         }
     380           0 :         if (r_geoms) {
     381           0 :                 for (BUN i = 0; i < r_ci.ncand; i++) {
     382           0 :                         GEOSGeom_destroy_r(geoshandle, r_geoms[i]);
     383             :                 }
     384           0 :                 GDKfree(r_geoms);
     385             :         }
     386           0 :         bat_iterator_end(&l_iter);
     387           0 :         bat_iterator_end(&r_iter);
     388           0 :         BBPunfix(l->batCacheid);
     389           0 :         BBPunfix(r->batCacheid);
     390           0 :         if (ls)
     391           0 :                 BBPunfix(ls->batCacheid);
     392           0 :         if (rs)
     393           0 :                 BBPunfix(rs->batCacheid);
     394           0 :         *lres_id = lres->batCacheid;
     395           0 :         BBPkeepref(lres);
     396           0 :         *rres_id = rres->batCacheid;
     397           0 :         BBPkeepref(rres);
     398           0 :         return MAL_SUCCEED;
     399           0 : free:
     400           0 :         if (l_geoms) {
     401           0 :                 for (BUN i = 0; i < l_ci.ncand; i++) {
     402           0 :                         GEOSGeom_destroy_r(geoshandle, l_geoms[i]);
     403             :                 }
     404           0 :                 GDKfree(l_geoms);
     405             :         }
     406           0 :         if (r_geoms) {
     407           0 :                 for (BUN i = 0; i < r_ci.ncand; i++) {
     408           0 :                         GEOSGeom_destroy_r(geoshandle, r_geoms[i]);
     409             :                 }
     410           0 :                 GDKfree(r_geoms);
     411             :         }
     412           0 :         BBPunfix(l->batCacheid);
     413           0 :         BBPunfix(r->batCacheid);
     414           0 :         if (ls)
     415           0 :                 BBPunfix(ls->batCacheid);
     416           0 :         if (rs)
     417           0 :                 BBPunfix(rs->batCacheid);
     418           0 :         if (lres)
     419           0 :                 BBPreclaim(lres);
     420           0 :         if (rres)
     421           0 :                 BBPreclaim(rres);
     422             :         return msg;
     423             : }
     424             : 
     425             : #ifdef HAVE_RTREE
     426             : static str
     427             : filterJoinRTree(bat *lres_id, bat *rres_id, const bat *l_id, const bat *r_id, double double_flag, const bat *ls_id, const bat *rs_id, bit nil_matches, lng estimate, bit anti, char (*func) (GEOSContextHandle_t handle, const GEOSGeometry *, const GEOSGeometry *, double), const char *name) {
     428             :         BAT *lres = NULL, *rres = NULL, *l = NULL, *r = NULL, *ls = NULL, *rs = NULL, *inner_res = NULL, *outer_res = NULL, *inner_b = NULL;
     429             :         BUN estimate_safe;
     430             :         BATiter l_iter, r_iter;
     431             :         str msg = MAL_SUCCEED;
     432             :         struct canditer l_ci, r_ci, outer_ci, inner_ci;
     433             :         GEOSGeom outer_geom, inner_geom;
     434             :         GEOSGeom *l_geoms = NULL, *r_geoms = NULL, *outer_geoms = NULL, *inner_geoms = NULL;
     435             : 
     436             :         //get the input BATs
     437             :         if ((l = BATdescriptor(*l_id)) == NULL || (r = BATdescriptor(*r_id)) == NULL) {
     438             :                 if (l)
     439             :                         BBPunfix(l->batCacheid);
     440             :                 if (r)
     441             :                         BBPunfix(r->batCacheid);
     442             :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     443             :         }
     444             :         //get the candidate lists
     445             :         if (ls_id && !is_bat_nil(*ls_id) && (ls = BATdescriptor(*ls_id)) == NULL && rs_id && !is_bat_nil(*rs_id) && (rs = BATdescriptor(*rs_id)) == NULL) {
     446             :                 msg = createException(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     447             :                 goto free;
     448             :         }
     449             :         canditer_init(&l_ci, l, ls);
     450             :         canditer_init(&r_ci, r, rs);
     451             : 
     452             :         // properly handle the estimate
     453             :         if (is_lng_nil(estimate) || estimate == 0) {
     454             :                 if (l_ci.ncand > r_ci.ncand)
     455             :                         estimate = l_ci.ncand;
     456             :                 else
     457             :                         estimate = r_ci.ncand;
     458             :         }
     459             : 
     460             :         if (estimate < 0 || is_lng_nil(estimate) || estimate > (lng) BUN_MAX)
     461             :                 estimate_safe = BUN_NONE;
     462             :         else
     463             :                 estimate_safe = (BUN) estimate;
     464             : 
     465             :         // create new BATs for the output
     466             :         if ((lres = COLnew(0, ATOMindex("oid"), estimate_safe, TRANSIENT)) == NULL) {
     467             :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     468             :                 goto free;
     469             :         }
     470             :         if ((rres = COLnew(0, ATOMindex("oid"), estimate_safe, TRANSIENT)) == NULL) {
     471             :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     472             :                 goto free;
     473             :         }
     474             : 
     475             :         //Allocate arrays for reutilizing GEOS type conversion
     476             :         if ((l_geoms = GDKmalloc(l_ci.ncand * sizeof(GEOSGeometry *))) == NULL || (r_geoms = GDKmalloc(r_ci.ncand * sizeof(GEOSGeometry *))) == NULL) {
     477             :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     478             :                 goto free;
     479             :         }
     480             : 
     481             :         l_iter = bat_iterator(l);
     482             :         r_iter = bat_iterator(r);
     483             : 
     484             :         //Convert wkb to GEOS only once
     485             :         for (BUN i = 0; i < l_ci.ncand; i++) {
     486             :                 oid l_oid = canditer_next(&l_ci);
     487             :                 l_geoms[i] = wkb2geos((const wkb*) BUNtvar(l_iter, l_oid - l->hseqbase));
     488             :         }
     489             :         for (BUN j = 0; j < r_ci.ncand; j++) {
     490             :                 oid r_oid = canditer_next(&r_ci);
     491             :                 r_geoms[j] = wkb2geos((const wkb*)BUNtvar(r_iter, r_oid - r->hseqbase));
     492             :         }
     493             : 
     494             :         bat_iterator_end(&l_iter);
     495             :         bat_iterator_end(&r_iter);
     496             : 
     497             :         if (l_ci.ncand > r_ci.ncand) {
     498             :                 inner_b = l;
     499             :                 inner_res = lres;
     500             :                 inner_ci = l_ci;
     501             :                 inner_geoms = l_geoms;
     502             :                 outer_res = rres;
     503             :                 outer_ci = r_ci;
     504             :                 outer_geoms = r_geoms;
     505             :         }
     506             :         else {
     507             :                 inner_b = r;
     508             :                 inner_res = rres;
     509             :                 inner_ci = r_ci;
     510             :                 inner_geoms = r_geoms;
     511             :                 outer_res = lres;
     512             :                 outer_ci = l_ci;
     513             :                 outer_geoms = l_geoms;
     514             :         }
     515             : 
     516             :         canditer_reset(&outer_ci);
     517             :         for (BUN i = 0; i < outer_ci.ncand; i++) {
     518             :                 oid outer_oid = canditer_next(&outer_ci);
     519             :                 outer_geom = outer_geoms[i];
     520             :                 if (!nil_matches && outer_geom == NULL)
     521             :                         continue;
     522             : 
     523             :                 //Calculate the MBR for the constant geometry
     524             :                 mbr *outer_mbr = mbrFromGeos(outer_geom);
     525             :                 BUN* results_rtree = RTREEsearch(inner_b,(mbr_t*)outer_mbr, outer_ci.ncand);
     526             :                 if (results_rtree == NULL) {
     527             :                         msg = createException(MAL, name, "RTreesearch failed, returned NULL candidates");
     528             :                         goto free;
     529             :                 }
     530             : 
     531             :                 canditer_reset(&inner_ci);
     532             :                 for (BUN j = 0; results_rtree[j] != BUN_NONE && j < inner_ci.ncand; j++) {
     533             :                         //oid inner_oid = canditer_next(&inner_ci);
     534             :                         oid inner_oid = results_rtree[j];
     535             :                         inner_geom = inner_geoms[j - inner_b->hseqbase];
     536             : 
     537             :                         if (inner_ci.tpe != cand_dense) {
     538             :                                 //If the original candidate list does not contain the rtree cand, move on to next one
     539             :                                 if (!canditer_contains(&inner_ci,inner_oid))
     540             :                                         continue;
     541             :                         }
     542             : 
     543             :                         //Null handling
     544             :                         if (inner_geom == NULL) {
     545             :                                 if (nil_matches && outer_geom == NULL) {
     546             :                                         if (BUNappend(outer_res, &outer_oid, false) != GDK_SUCCEED || BUNappend(inner_res, &inner_oid, false) != GDK_SUCCEED) {
     547             :                                                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     548             :                                                 goto free;
     549             :                                         }
     550             :                                 }
     551             :                                 else
     552             :                                         continue;
     553             :                         }
     554             :                         if (GEOSGetSRID_r(geoshandle, outer_geom) != GEOSGetSRID_r(geoshandle, inner_geom)) {
     555             :                                 msg = createException(MAL, name, SQLSTATE(38000) "Geometries of different SRID");
     556             :                                 goto free;
     557             :                         }
     558             :                         //Apply the (Geom, Geom, double) -> bit function
     559             :                         bit cond = (*func)(geoshandle, inner_geom, outer_geom, double_flag) == 1;
     560             :                         if (cond != anti) {
     561             :                                 if (BUNappend(inner_res, &inner_oid, false) != GDK_SUCCEED || BUNappend(outer_res, &outer_oid, false) != GDK_SUCCEED) {
     562             :                                         msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     563             :                                         goto free;
     564             :                                 }
     565             :                         }
     566             :                 }
     567             :         }
     568             :         if (l_geoms) {
     569             :                 for (BUN i = 0; i < l_ci.ncand; i++) {
     570             :                         GEOSGeom_destroy_r(geoshandle, l_geoms[i]);
     571             :                 }
     572             :                 GDKfree(l_geoms);
     573             :         }
     574             :         if (r_geoms) {
     575             :                 for (BUN i = 0; i < r_ci.ncand; i++) {
     576             :                         GEOSGeom_destroy_r(geoshandle, r_geoms[i]);
     577             :                 }
     578             :                 GDKfree(r_geoms);
     579             :         }
     580             :         BBPunfix(l->batCacheid);
     581             :         BBPunfix(r->batCacheid);
     582             :         if (ls)
     583             :                 BBPunfix(ls->batCacheid);
     584             :         if (rs)
     585             :                 BBPunfix(rs->batCacheid);
     586             :         *lres_id = lres->batCacheid;
     587             :         BBPkeepref(lres);
     588             :         *rres_id = rres->batCacheid;
     589             :         BBPkeepref(rres);
     590             :         return MAL_SUCCEED;
     591             : free:
     592             :         if (l_geoms) {
     593             :                 for (BUN i = 0; i < l_ci.ncand; i++) {
     594             :                         GEOSGeom_destroy_r(geoshandle, l_geoms[i]);
     595             :                 }
     596             :                 GDKfree(l_geoms);
     597             :         }
     598             :         if (r_geoms) {
     599             :                 for (BUN i = 0; i < r_ci.ncand; i++) {
     600             :                         GEOSGeom_destroy_r(geoshandle, r_geoms[i]);
     601             :                 }
     602             :                 GDKfree(r_geoms);
     603             :         }
     604             :         BBPunfix(l->batCacheid);
     605             :         BBPunfix(r->batCacheid);
     606             :         if (ls)
     607             :                 BBPunfix(ls->batCacheid);
     608             :         if (rs)
     609             :                 BBPunfix(rs->batCacheid);
     610             :         if (lres)
     611             :                 BBPreclaim(lres);
     612             :         if (rres)
     613             :                 BBPreclaim(rres);
     614             :         return msg;
     615             : }
     616             : #endif
     617             : 
     618             : str
     619           0 : wkbIntersectsJoinRTree(bat *lres_id, bat *rres_id, const bat *l_id, const bat *r_id, const bat *ls_id, const bat *rs_id, bit *nil_matches, lng *estimate, bit *anti) {
     620             : #ifdef HAVE_RTREE
     621             :         //If there is an RTree on memory or on file, use the RTree method. Otherwise, use the no index version.
     622             :         if (RTREEexists_bid((bat*)l_id) && RTREEexists_bid((bat*)r_id))
     623             :                 return filterJoinRTree(lres_id,rres_id,l_id,r_id,0,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsJoinRTree");
     624             :         else
     625             :                 return filterJoinNoIndex(lres_id,rres_id,l_id,r_id,0,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsJoinNoIndex");
     626             : 
     627             : #else
     628           0 :         return filterJoinNoIndex(lres_id,rres_id,l_id,r_id,0,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsJoinNoIndex");
     629             : #endif
     630             : }
     631             : 
     632             : str
     633           0 : wkbDWithinJoinRTree(bat *lres_id, bat *rres_id, const bat *l_id, const bat *r_id, const bat *ls_id, const bat *rs_id, dbl *distance, bit *nil_matches, lng *estimate, bit *anti) {
     634             : #ifdef HAVE_RTREE
     635             :         if (RTREEexists_bid((bat*)l_id) && RTREEexists_bid((bat*)r_id))
     636             :                 return filterJoinRTree(lres_id,rres_id,l_id,r_id,*distance,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbDWithinJoinRTree");
     637             :         else
     638             :                 return filterJoinNoIndex(lres_id,rres_id,l_id,r_id,*distance,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbDWithinJoinNoIndex");
     639             : #else
     640           0 :         return filterJoinNoIndex(lres_id,rres_id,l_id,r_id,*distance,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbDWithinJoinNoIndex");
     641             : #endif
     642             : }
     643             : 
     644             : str
     645           0 : wkbIntersectsJoinNoIndex(bat *lres_id, bat *rres_id, const bat *l_id, const bat *r_id, const bat *ls_id, const bat *rs_id, bit *nil_matches, lng *estimate, bit *anti) {
     646           0 :         return filterJoinNoIndex(lres_id,rres_id,l_id,r_id,0,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbIntersectsJoinNoIndex");
     647             : }
     648             : 
     649             : str
     650           0 : wkbDWithinJoinNoIndex(bat *lres_id, bat *rres_id, const bat *l_id, const bat *r_id, const bat *ls_id, const bat *rs_id, double *distance, bit *nil_matches, lng *estimate, bit *anti) {
     651           0 :         return filterJoinNoIndex(lres_id,rres_id,l_id,r_id,*distance,ls_id,rs_id,*nil_matches,*estimate,*anti,GEOSDistanceWithin_r,"geom.wkbDWithinJoinNoIndex");
     652             : }
     653             : 
     654             : //MBR bulk function
     655             : //Creates the BAT with MBRs from the input BAT with WKB geometries
     656             : //Also creates the RTree structure and saves it on the WKB input BAT
     657             : str
     658          13 : wkbMBR_bat(bat *outBAT_id, bat *inBAT_id)
     659             : {
     660          13 :         BAT *outBAT = NULL, *inBAT = NULL;
     661          13 :         wkb *inWKB = NULL;
     662          13 :         mbr *outMBR = NULL;
     663          13 :         BUN p = 0, q = 0;
     664          13 :         BATiter inBAT_iter;
     665             : 
     666          13 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
     667           0 :                 throw(MAL, "batgeom.mbr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     668             :         }
     669          13 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("mbr"), BATcount(inBAT), TRANSIENT)) == NULL) {
     670           0 :                 BBPunfix(inBAT->batCacheid);
     671           0 :                 throw(MAL, "batgeom.mbr", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     672             :         }
     673             : 
     674          13 :         inBAT_iter = bat_iterator(inBAT);
     675         177 :         BATloop(inBAT, p, q) {
     676         164 :                 str err = NULL;
     677             : 
     678         164 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
     679         164 :                 if ((err = wkbMBR(&outMBR, &inWKB)) != MAL_SUCCEED) {
     680           0 :                         bat_iterator_end(&inBAT_iter);
     681           0 :                         BBPunfix(inBAT->batCacheid);
     682           0 :                         BBPunfix(outBAT->batCacheid);
     683           0 :                         return err;
     684             :                 }
     685         164 :                 if (BUNappend(outBAT, outMBR, false) != GDK_SUCCEED) {
     686           0 :                         bat_iterator_end(&inBAT_iter);
     687           0 :                         BBPunfix(inBAT->batCacheid);
     688           0 :                         BBPunfix(outBAT->batCacheid);
     689           0 :                         GDKfree(outMBR);
     690           0 :                         throw(MAL, "batgeom.mbr", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     691             :                 }
     692         163 :                 GDKfree(outMBR);
     693         164 :                 outMBR = NULL;
     694             :         }
     695          13 :         bat_iterator_end(&inBAT_iter);
     696          13 :         BBPunfix(inBAT->batCacheid);
     697             : 
     698          13 :         *outBAT_id = outBAT->batCacheid;
     699             : 
     700             : #ifdef HAVE_RTREE
     701             :         //Build RTree index using the mbr's we just calculated, and save it on the wkb BAT
     702             :         BATrtree(inBAT,outBAT);
     703             : #endif
     704          13 :         BBPkeepref(outBAT);
     705          13 :         return MAL_SUCCEED;
     706             : }
     707             : 
     708             : /* ST_Transform Bulk function */
     709             : str
     710           0 : wkbTransform_bat(bat *outBAT_id, bat *inBAT_id, int *srid_src, int *srid_dst, char **proj4_src_str, char **proj4_dst_str)
     711             : {
     712           0 :         return wkbTransform_bat_cand(outBAT_id,inBAT_id,NULL,srid_src,srid_dst,proj4_src_str,proj4_dst_str);
     713             : }
     714             : 
     715             : str
     716           0 : wkbTransform_bat_cand(bat *outBAT_id, bat *inBAT_id, bat *s_id, int *srid_src, int *srid_dst, char **proj4_src_str, char **proj4_dst_str)
     717             : {
     718             : #ifndef HAVE_PROJ
     719             :         *outBAT_id = 0;
     720             :         (void) inBAT_id;
     721             :         (void) s_id;
     722             :         (void) srid_src;
     723             :         (void) srid_dst;
     724             :         (void) proj4_src_str;
     725             :         (void) proj4_dst_str;
     726             :         throw(MAL, "geom.Transform", SQLSTATE(38000) "PROJ library not found");
     727             : #else
     728           0 :         BAT *outBAT = NULL, *inBAT = NULL, *s = NULL;;
     729           0 :         BATiter inBAT_iter;
     730           0 :         str err = MAL_SUCCEED;
     731           0 :         struct canditer ci;
     732             : 
     733           0 :         PJ *P;
     734           0 :         GEOSGeom geosGeometry, transformedGeosGeometry;
     735           0 :         const wkb *geomWKB = NULL;
     736           0 :         wkb *transformedWKB;
     737           0 :         int geometryType = -1;
     738             : 
     739           0 :         if (is_int_nil(*srid_src) ||
     740           0 :             is_int_nil(*srid_dst) ||
     741           0 :             strNil(*proj4_src_str) ||
     742           0 :             strNil(*proj4_dst_str)) {
     743             :                 //TODO: What do we return here?
     744             :                 return MAL_SUCCEED;
     745             :         }
     746             : 
     747           0 :         if (strcmp(*proj4_src_str, "null") == 0)
     748           0 :                 throw(MAL, "batgeom.Transform", SQLSTATE(38000) "Cannot find in spatial_ref_sys srid %d\n", *srid_src);
     749           0 :         if (strcmp(*proj4_dst_str, "null") == 0)
     750           0 :                 throw(MAL, "batgeom.Transform", SQLSTATE(38000) "Cannot find in spatial_ref_sys srid %d\n", *srid_dst);
     751           0 :         if (strcmp(*proj4_src_str, *proj4_dst_str) == 0) {
     752             :                 //TODO: Return a copy of the input BAT
     753             :                 return MAL_SUCCEED;
     754             :         }
     755             : 
     756             :         //Create PROJ transformation object with PROJ strings passed as argument
     757           0 :         P = proj_create_crs_to_crs(PJ_DEFAULT_CTX,
     758             :                                *proj4_src_str,
     759             :                                *proj4_dst_str,
     760             :                                NULL);
     761           0 :         if (P==0)
     762           0 :         throw(MAL, "batgeom.Transform", SQLSTATE(38000) "PROJ initialization failed");
     763             : 
     764             :         //get the descriptor of the BAT
     765           0 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
     766           0 :                 proj_destroy(P);
     767           0 :                 throw(MAL, "batgeom.Transform", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     768             :         }
     769             : 
     770             :         //create a new for the output BAT
     771           0 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT), TRANSIENT)) == NULL) {
     772           0 :                 BBPunfix(inBAT->batCacheid);
     773           0 :                 proj_destroy(P);
     774           0 :                 throw(MAL, "batgeom.Transform", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     775             :         }
     776             : 
     777             :         //check for candidate lists
     778           0 :         if (s_id && !is_bat_nil(*s_id) && (s = BATdescriptor(*s_id)) == NULL) {
     779           0 :                 BBPunfix(inBAT->batCacheid);
     780           0 :                 BBPunfix(outBAT->batCacheid);
     781           0 :                 proj_destroy(P);
     782           0 :                 throw(MAL, "batgeom.Transform", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     783             :         }
     784           0 :         canditer_init(&ci, inBAT, s);
     785             : 
     786             :         //iterator over the input BAT
     787           0 :         inBAT_iter = bat_iterator(inBAT);
     788           0 :         for (BUN i = 0; i < ci.ncand && err == MAL_SUCCEED; i++) {
     789           0 :                 oid p = (canditer_next(&ci) - inBAT->hseqbase);
     790           0 :                 geomWKB = (wkb *) BUNtvar(inBAT_iter, p);
     791             : 
     792             :                 /* get the geosGeometry from the wkb */
     793           0 :                 geosGeometry = wkb2geos(geomWKB);
     794             :                 /* get the type of the geometry */
     795           0 :                 geometryType = GEOSGeomTypeId_r(geoshandle, geosGeometry) + 1;
     796             : 
     797             :                 //TODO: No collection?
     798           0 :                 switch (geometryType) {
     799           0 :                 case wkbPoint_mdb:
     800           0 :                         err = transformPoint(&transformedGeosGeometry, geosGeometry, P);
     801           0 :                         break;
     802           0 :                 case wkbLineString_mdb:
     803           0 :                         err = transformLineString(&transformedGeosGeometry, geosGeometry, P);
     804           0 :                         break;
     805           0 :                 case wkbLinearRing_mdb:
     806           0 :                         err = transformLinearRing(&transformedGeosGeometry, geosGeometry, P);
     807           0 :                         break;
     808           0 :                 case wkbPolygon_mdb:
     809           0 :                         err = transformPolygon(&transformedGeosGeometry, geosGeometry, P, *srid_dst);
     810           0 :                         break;
     811           0 :                 case wkbMultiPoint_mdb:
     812             :                 case wkbMultiLineString_mdb:
     813             :                 case wkbMultiPolygon_mdb:
     814           0 :                         err = transformMultiGeometry(&transformedGeosGeometry, geosGeometry, P, *srid_dst, geometryType);
     815           0 :                         break;
     816           0 :                 default:
     817           0 :                         transformedGeosGeometry = NULL;
     818           0 :                         err = createException(MAL, "batgeom.Transform", SQLSTATE(38000) "Geos unknown geometry type");
     819             :                 }
     820             : 
     821           0 :                 if (err == MAL_SUCCEED && transformedGeosGeometry) {
     822             :                         /* set the new srid */
     823           0 :                         GEOSSetSRID_r(geoshandle, transformedGeosGeometry, *srid_dst);
     824             :                         /* get the wkb */
     825           0 :                         if ((transformedWKB = geos2wkb(transformedGeosGeometry)) == NULL)
     826           0 :                                 throw(MAL, "batgeom.Transform", SQLSTATE(38000) "Geos operation geos2wkb failed");
     827             :                         else {
     828           0 :                                 if (BUNappend(outBAT, transformedWKB, false) != GDK_SUCCEED) {
     829           0 :                                         throw(MAL, "batgeom.Transform", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     830             :                                 }
     831             :                         }
     832             : 
     833             :                         /* destroy the geos geometries */
     834           0 :                         GEOSGeom_destroy_r(geoshandle, transformedGeosGeometry);
     835             : 
     836             :                 }
     837           0 :                 GEOSGeom_destroy_r(geoshandle, geosGeometry);
     838             :         }
     839           0 :         proj_destroy(P);
     840           0 :         bat_iterator_end(&inBAT_iter);
     841             : 
     842           0 :         BBPunfix(inBAT->batCacheid);
     843           0 :         if (s)
     844           0 :                 BBPunfix(s->batCacheid);
     845           0 :         *outBAT_id = outBAT->batCacheid;
     846           0 :         BBPkeepref(outBAT);
     847             : 
     848           0 :         return MAL_SUCCEED;
     849             : #endif
     850             : }
     851             : 
     852             : /* ST_DistanceGeographic Bulk function */
     853             : str
     854           0 : wkbDistanceGeographic_bat(bat *out_id, const bat *a_id, const bat *b_id)
     855             : {
     856           0 :         return wkbDistanceGeographic_bat_cand(out_id,a_id,b_id,NULL,NULL);
     857             : }
     858             : 
     859             : str
     860           0 : wkbDistanceGeographic_bat_cand(bat *out_id, const bat *a_id, const bat *b_id, const bat *s1_id, const bat *s2_id)
     861             : {
     862           0 :         BAT *out = NULL, *a = NULL, *b = NULL, *s1 = NULL, *s2 = NULL;
     863           0 :         BATiter a_iter, b_iter;
     864           0 :         str msg = MAL_SUCCEED;
     865           0 :         struct canditer ci1, ci2;
     866             : 
     867             :         //get the BATs
     868           0 :         if ((a = BATdescriptor(*a_id)) == NULL || (b = BATdescriptor(*b_id)) == NULL) {
     869           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     870           0 :                 goto clean;
     871             :         }
     872             :         //check if the BATs are aligned
     873           0 :         if (a->hseqbase != b->hseqbase || BATcount(a) != BATcount(b)) {
     874           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(38000) "Columns must be aligned");
     875           0 :                 goto clean;
     876             :         }
     877             :         //check for candidate lists
     878           0 :         if (s1_id && !is_bat_nil(*s1_id) && (s1 = BATdescriptor(*s1_id)) == NULL) {
     879           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     880           0 :                 goto clean;
     881             :         }
     882           0 :         if (s2_id && !is_bat_nil(*s2_id) && (s2 = BATdescriptor(*s2_id)) == NULL) {
     883           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     884           0 :                 if (s1)
     885           0 :                         BBPunfix(s1->batCacheid);
     886           0 :                 goto clean;
     887             :         }
     888           0 :         canditer_init(&ci1, a, s1);
     889           0 :         canditer_init(&ci2, b, s2);
     890             : 
     891             :         //create a new BAT for the output
     892           0 :         if ((out = COLnew(0, ATOMindex("dbl"), ci1.ncand, TRANSIENT)) == NULL) {
     893           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     894           0 :                 if (s1)
     895           0 :                         BBPunfix(s1->batCacheid);
     896           0 :                 if (s2)
     897           0 :                         BBPunfix(s2->batCacheid);
     898           0 :                 goto clean;
     899             :         }
     900             :         //iterator over the BATs
     901           0 :         a_iter = bat_iterator(a);
     902           0 :         b_iter = bat_iterator(b);
     903             : 
     904           0 :         for (BUN i = 0; i < ci1.ncand; i++) {
     905           0 :                 double distanceVal = 0;
     906           0 :                 oid p1 = (canditer_next(&ci1) - a->hseqbase);
     907           0 :                 oid p2 = (canditer_next(&ci2) - b->hseqbase);
     908           0 :                 wkb *aWKB = (wkb *) BUNtvar(a_iter, p1);
     909           0 :                 wkb *bWKB = (wkb *) BUNtvar(b_iter, p2);
     910             : 
     911           0 :                 if ((msg = wkbDistanceGeographic(&distanceVal, &aWKB, &bWKB)) != MAL_SUCCEED) {
     912           0 :                         BBPreclaim(out);
     913           0 :                         goto bailout;
     914             :                 }
     915           0 :                 if (BUNappend(out, &distanceVal, false) != GDK_SUCCEED) {
     916           0 :                         BBPreclaim(out);
     917           0 :                         msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     918           0 :                         goto bailout;
     919             :                 }
     920             :         }
     921           0 :         *out_id = out->batCacheid;
     922           0 :         BBPkeepref(out);
     923           0 : bailout:
     924           0 :         bat_iterator_end(&a_iter);
     925           0 :         bat_iterator_end(&b_iter);
     926           0 :         BBPreclaim(s1);
     927           0 :         BBPreclaim(s2);
     928           0 : clean:
     929           0 :         BBPreclaim(a);
     930           0 :         BBPreclaim(b);
     931           0 :         BBPreclaim(out);
     932           0 :         return msg;
     933             : }
     934             : 
     935             : /********** Geo Update End **********/
     936             : 
     937             : /*******************************/
     938             : /********** One input **********/
     939             : /*******************************/
     940             : 
     941             : str
     942           1 : geom_2_geom_bat(bat *outBAT_id, bat *inBAT_id, bat *cand, int *columnType, int *columnSRID)
     943             : {
     944           1 :         BAT *b = NULL, *s = NULL, *dst = NULL;
     945           1 :         BATiter bi;
     946           1 :         str msg = MAL_SUCCEED;
     947           1 :         struct canditer ci;
     948           1 :         oid off = 0;
     949           1 :         bool nils = false;
     950           1 :         wkb *inWKB = NULL, *outWKB = NULL;
     951             : 
     952             :         //get the descriptor of the BAT
     953           1 :         if ((b = BATdescriptor(*inBAT_id)) == NULL) {
     954           0 :                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     955           0 :                 goto bailout;
     956             :         }
     957           1 :         bi = bat_iterator(b);
     958           1 :         if (cand && !is_bat_nil(*cand) && (s = BATdescriptor(*cand)) == NULL) {
     959           0 :                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     960           0 :                 goto bailout;
     961             :         }
     962           1 :         off = b->hseqbase;
     963           1 :         canditer_init(&ci, b, s);
     964             :         //create a new BAT, aligned with input BAT
     965           1 :         if ((dst = COLnew(ci.hseq, ATOMindex("wkb"), ci.ncand, TRANSIENT)) == NULL) {
     966           0 :                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     967           0 :                 goto bailout;
     968             :         }
     969             : 
     970           1 :         if (ci.tpe == cand_dense) {
     971           4 :                 for (BUN i = 0; i < ci.ncand; i++) {
     972           3 :                         oid p = (canditer_next_dense(&ci) - off);
     973           3 :                         inWKB = (wkb *) BUNtvar(bi, p);
     974             : 
     975           3 :                         if ((msg = geom_2_geom(&outWKB, &inWKB, columnType, columnSRID)) != MAL_SUCCEED)        //check type
     976           0 :                                 goto bailout;
     977           3 :                         if (tfastins_nocheckVAR(dst, i, outWKB) != GDK_SUCCEED) {
     978           0 :                                 GDKfree(outWKB);
     979           0 :                                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     980           0 :                                 goto bailout;
     981             :                         }
     982           3 :                         nils |= is_wkb_nil(outWKB);
     983           3 :                         GDKfree(outWKB);
     984           3 :                         outWKB = NULL;
     985             :                 }
     986             :         } else {
     987           0 :                 for (BUN i = 0; i < ci.ncand; i++) {
     988           0 :                         oid p = (canditer_next(&ci) - off);
     989           0 :                         inWKB = (wkb *) BUNtvar(bi, p);
     990             : 
     991           0 :                         if ((msg = geom_2_geom(&outWKB, &inWKB, columnType, columnSRID)) != MAL_SUCCEED)        //check type
     992           0 :                                 goto bailout;
     993           0 :                         if (tfastins_nocheckVAR(dst, i, outWKB) != GDK_SUCCEED) {
     994           0 :                                 GDKfree(outWKB);
     995           0 :                                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     996           0 :                                 goto bailout;
     997             :                         }
     998           0 :                         nils |= is_wkb_nil(outWKB);
     999           0 :                         GDKfree(outWKB);
    1000           0 :                         outWKB = NULL;
    1001             :                 }
    1002             :         }
    1003             : 
    1004           0 : bailout:
    1005           1 :         if (b) {
    1006           1 :                 bat_iterator_end(&bi);
    1007           1 :                 BBPunfix(b->batCacheid);
    1008             :         }
    1009           1 :         BBPreclaim(s);
    1010           1 :         if (dst && !msg) {
    1011           1 :                 BATsetcount(dst, ci.ncand);
    1012           1 :                 dst->tnil = nils;
    1013           1 :                 dst->tnonil = !nils;
    1014           1 :                 dst->tkey = BATcount(dst) <= 1;
    1015           1 :                 dst->tsorted = BATcount(dst) <= 1;
    1016           1 :                 dst->trevsorted = BATcount(dst) <= 1;
    1017           1 :                 *outBAT_id = dst->batCacheid;
    1018           1 :                 BBPkeepref(dst);
    1019           0 :         } else if (dst)
    1020           0 :                 BBPreclaim(dst);
    1021           1 :         return msg;
    1022             : }
    1023             : 
    1024             : /*create WKB from WKT */
    1025             : str
    1026          49 : wkbFromText_bat(bat *outBAT_id, bat *inBAT_id, int *srid, int *tpe)
    1027             : {
    1028          49 :         return wkbFromText_bat_cand(outBAT_id, inBAT_id, NULL, srid, tpe);
    1029             : }
    1030             : 
    1031             : str
    1032          53 : wkbFromText_bat_cand(bat *outBAT_id, bat *inBAT_id, bat *cand, int *srid, int *tpe)
    1033             : {
    1034          53 :         BAT *b = NULL, *s = NULL, *dst = NULL;
    1035          53 :         BATiter bi;
    1036          53 :         str msg = MAL_SUCCEED;
    1037          53 :         struct canditer ci;
    1038          53 :         oid off = 0;
    1039          53 :         bool nils = false;
    1040             : 
    1041             :         //get the descriptor of the BAT
    1042          53 :         if ((b = BATdescriptor(*inBAT_id)) == NULL) {
    1043           0 :                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1044           0 :                 goto bailout;
    1045             :         }
    1046          53 :         bi = bat_iterator(b);
    1047          53 :         if (cand && !is_bat_nil(*cand) && (s = BATdescriptor(*cand)) == NULL) {
    1048           0 :                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1049           0 :                 goto bailout;
    1050             :         }
    1051          53 :         off = b->hseqbase;
    1052          53 :         canditer_init(&ci, b, s);
    1053             :         //create a new BAT, aligned with input BAT
    1054          53 :         if ((dst = COLnew(ci.hseq, ATOMindex("wkb"), ci.ncand, TRANSIENT)) == NULL) {
    1055           0 :                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1056           0 :                 goto bailout;
    1057             :         }
    1058             : 
    1059          53 :         if (ci.tpe == cand_dense) {
    1060          78 :                 for (BUN i = 0; i < ci.ncand; i++) {
    1061          68 :                         oid p = (canditer_next_dense(&ci) - off);
    1062          68 :                         str inWKB = (str) BUNtvar(bi, p);
    1063          68 :                         wkb *outSingle;
    1064             : 
    1065          68 :                         if ((msg = wkbFromText(&outSingle, &inWKB, srid, tpe)) != MAL_SUCCEED)
    1066          43 :                                 goto bailout;
    1067          25 :                         if (tfastins_nocheckVAR(dst, i, outSingle) != GDK_SUCCEED) {
    1068           0 :                                 GDKfree(outSingle);
    1069           0 :                                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1070           0 :                                 goto bailout;
    1071             :                         }
    1072          25 :                         nils |= is_wkb_nil(outSingle);
    1073          25 :                         GDKfree(outSingle);
    1074          25 :                         outSingle = NULL;
    1075             :                 }
    1076             :         } else {
    1077           0 :                 for (BUN i = 0; i < ci.ncand; i++) {
    1078           0 :                         oid p = (canditer_next(&ci) - off);
    1079           0 :                         str inWKB = (str) BUNtvar(bi, p);
    1080           0 :                         wkb *outSingle;
    1081             : 
    1082           0 :                         if ((msg = wkbFromText(&outSingle, &inWKB, srid, tpe)) != MAL_SUCCEED)
    1083           0 :                                 goto bailout;
    1084           0 :                         if (tfastins_nocheckVAR(dst, i, outSingle) != GDK_SUCCEED) {
    1085           0 :                                 GDKfree(outSingle);
    1086           0 :                                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1087           0 :                                 goto bailout;
    1088             :                         }
    1089           0 :                         nils |= is_wkb_nil(outSingle);
    1090           0 :                         GDKfree(outSingle);
    1091           0 :                         outSingle = NULL;
    1092             :                 }
    1093             :         }
    1094             : 
    1095           0 : bailout:
    1096          53 :         if (b) {
    1097          53 :                 bat_iterator_end(&bi);
    1098          53 :                 BBPunfix(b->batCacheid);
    1099             :         }
    1100          53 :         BBPreclaim(s);
    1101          53 :         if (dst && !msg) {
    1102          10 :                 BATsetcount(dst, ci.ncand);
    1103          10 :                 dst->tnil = nils;
    1104          10 :                 dst->tnonil = !nils;
    1105          10 :                 dst->tkey = BATcount(dst) <= 1;
    1106          10 :                 dst->tsorted = BATcount(dst) <= 1;
    1107          10 :                 dst->trevsorted = BATcount(dst) <= 1;
    1108          10 :                 *outBAT_id = dst->batCacheid;
    1109          10 :                 BBPkeepref(dst);
    1110          43 :         } else if (dst)
    1111          43 :                 BBPreclaim(dst);
    1112          53 :         return msg;
    1113             : }
    1114             : 
    1115             : /*****************************************************************************/
    1116             : /********************* IN: mbr - OUT: double - FLAG :int *********************/
    1117             : /*****************************************************************************/
    1118             : str
    1119           8 : wkbCoordinateFromMBR_bat(bat *outBAT_id, bat *inBAT_id, int *coordinateIdx)
    1120             : {
    1121           8 :         BAT *outBAT = NULL, *inBAT = NULL;
    1122           8 :         mbr *inMBR = NULL;
    1123           8 :         double outDbl = 0.0;
    1124           8 :         BUN p = 0, q = 0;
    1125           8 :         BATiter inBAT_iter;
    1126             : 
    1127             :         //get the descriptor of the BAT
    1128           8 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1129           0 :                 throw(MAL, "batgeom.coordinateFromMBR", SQLSTATE(38000) RUNTIME_OBJECT_MISSING);
    1130             :         }
    1131             : 
    1132             :         //create a new BAT for the output
    1133           8 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("dbl"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1134           0 :                 BBPunfix(inBAT->batCacheid);
    1135           0 :                 throw(MAL, "batgeom.coordinateFromMBR", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1136             :         }
    1137             : 
    1138             :         //iterator over the BAT
    1139           8 :         inBAT_iter = bat_iterator(inBAT);
    1140         224 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1141         216 :                 str err = NULL;
    1142             : 
    1143         216 :                 inMBR = (mbr *) BUNtloc(inBAT_iter, p);
    1144         216 :                 if ((err = wkbCoordinateFromMBR(&outDbl, &inMBR, coordinateIdx)) != MAL_SUCCEED) {
    1145           0 :                         bat_iterator_end(&inBAT_iter);
    1146           0 :                         BBPunfix(inBAT->batCacheid);
    1147           0 :                         BBPunfix(outBAT->batCacheid);
    1148           0 :                         return err;
    1149             :                 }
    1150         216 :                 if (BUNappend(outBAT, &outDbl, false) != GDK_SUCCEED) {
    1151           0 :                         bat_iterator_end(&inBAT_iter);
    1152           0 :                         BBPunfix(inBAT->batCacheid);
    1153           0 :                         BBPunfix(outBAT->batCacheid);
    1154           0 :                         throw(MAL, "batgeom.coordinateFromMBR", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1155             :                 }
    1156             :         }
    1157           8 :         bat_iterator_end(&inBAT_iter);
    1158             : 
    1159           8 :         BBPunfix(inBAT->batCacheid);
    1160           8 :         *outBAT_id = outBAT->batCacheid;
    1161           8 :         BBPkeepref(outBAT);
    1162           8 :         return MAL_SUCCEED;
    1163             : 
    1164             : }
    1165             : 
    1166             : /**************************************************************************/
    1167             : /********************* IN: wkb - OUT: str - FLAG :int *********************/
    1168             : /**************************************************************************/
    1169             : static str
    1170          45 : WKBtoSTRflagINT_bat(bat *outBAT_id, bat *inBAT_id, int *flag, str (*func) (char **, wkb **, int *), const char *name)
    1171             : {
    1172          45 :         BAT *outBAT = NULL, *inBAT = NULL;
    1173          45 :         wkb *inWKB = NULL;
    1174          45 :         BUN p = 0, q = 0;
    1175          45 :         BATiter inBAT_iter;
    1176             : 
    1177             :         //get the descriptor of the BAT
    1178          45 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1179           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1180             :         }
    1181             : 
    1182             :         //create a new for the output BAT
    1183          45 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("str"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1184           0 :                 BBPunfix(inBAT->batCacheid);
    1185           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1186             :         }
    1187             : 
    1188             :         //iterator over the input BAT
    1189          45 :         inBAT_iter = bat_iterator(inBAT);
    1190         127 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1191          82 :                 str err = NULL;
    1192          82 :                 char *outSingle;
    1193             : 
    1194          82 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1195          82 :                 if ((err = (*func) (&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1196           0 :                         bat_iterator_end(&inBAT_iter);
    1197           0 :                         BBPunfix(inBAT->batCacheid);
    1198           0 :                         BBPunfix(outBAT->batCacheid);
    1199           0 :                         return err;
    1200             :                 }
    1201          82 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1202           0 :                         bat_iterator_end(&inBAT_iter);
    1203           0 :                         BBPunfix(inBAT->batCacheid);
    1204           0 :                         BBPunfix(outBAT->batCacheid);
    1205           0 :                         GDKfree(outSingle);
    1206           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1207             :                 }
    1208          82 :                 GDKfree(outSingle);
    1209          82 :                 outSingle = NULL;
    1210             :         }
    1211          45 :         bat_iterator_end(&inBAT_iter);
    1212             : 
    1213             :         //set the number of elements in the outBAT
    1214          45 :         BATsetcount(outBAT, BATcount(inBAT));
    1215             : 
    1216          45 :         BBPunfix(inBAT->batCacheid);
    1217          45 :         *outBAT_id = outBAT->batCacheid;
    1218          45 :         BBPkeepref(outBAT);
    1219             : 
    1220          45 :         return MAL_SUCCEED;
    1221             : }
    1222             : 
    1223             : /*create textual representation of the wkb */
    1224             : str
    1225          32 : wkbAsText_bat(bat *outBAT_id, bat *inBAT_id, int *withSRID)
    1226             : {
    1227          32 :         return WKBtoSTRflagINT_bat(outBAT_id, inBAT_id, withSRID, wkbAsText, "batgeom.wkbAsText");
    1228             : }
    1229             : 
    1230             : str
    1231          13 : wkbGeometryType_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1232             : {
    1233          13 :         return WKBtoSTRflagINT_bat(outBAT_id, inBAT_id, flag, wkbGeometryType, "batgeom.wkbGeometryType");
    1234             : }
    1235             : 
    1236             : /***************************************************************************/
    1237             : /*************************** IN: wkb - OUT: wkb ****************************/
    1238             : /***************************************************************************/
    1239             : 
    1240             : static str
    1241           5 : WKBtoWKB_bat(bat *outBAT_id, bat *inBAT_id, str (*func) (wkb **, wkb **), const char *name)
    1242             : {
    1243           5 :         BAT *outBAT = NULL, *inBAT = NULL;
    1244           5 :         wkb *inWKB = NULL;
    1245           5 :         BUN p = 0, q = 0;
    1246           5 :         BATiter inBAT_iter;
    1247             : 
    1248             :         //get the descriptor of the BAT
    1249           5 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1250           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1251             :         }
    1252             : 
    1253             :         //create a new for the output BAT
    1254           5 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1255           0 :                 BBPunfix(inBAT->batCacheid);
    1256           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1257             :         }
    1258             : 
    1259             :         //iterator over the input BAT
    1260           5 :         inBAT_iter = bat_iterator(inBAT);
    1261          29 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1262          24 :                 str err = NULL;
    1263          24 :                 wkb *outSingle;
    1264             : 
    1265          24 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1266          24 :                 if ((err = (*func) (&outSingle, &inWKB)) != MAL_SUCCEED) {
    1267           0 :                         bat_iterator_end(&inBAT_iter);
    1268           0 :                         BBPunfix(inBAT->batCacheid);
    1269           0 :                         BBPunfix(outBAT->batCacheid);
    1270           0 :                         return err;
    1271             :                 }
    1272          24 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1273           0 :                         bat_iterator_end(&inBAT_iter);
    1274           0 :                         BBPunfix(inBAT->batCacheid);
    1275           0 :                         BBPunfix(outBAT->batCacheid);
    1276           0 :                         GDKfree(outSingle);
    1277           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1278             :                 }
    1279          24 :                 GDKfree(outSingle);
    1280          24 :                 outSingle = NULL;
    1281             :         }
    1282           5 :         bat_iterator_end(&inBAT_iter);
    1283             : 
    1284             :         //set the number of elements in the outBAT
    1285           5 :         BATsetcount(outBAT, BATcount(inBAT));
    1286             : 
    1287           5 :         BBPunfix(inBAT->batCacheid);
    1288           5 :         *outBAT_id = outBAT->batCacheid;
    1289           5 :         BBPkeepref(outBAT);
    1290             : 
    1291           5 :         return MAL_SUCCEED;
    1292             : }
    1293             : 
    1294             : str
    1295           5 : wkbBoundary_bat(bat *outBAT_id, bat *inBAT_id)
    1296             : {
    1297           5 :         return WKBtoWKB_bat(outBAT_id, inBAT_id, wkbBoundary, "batgeom.wkbBoundary");
    1298             : }
    1299             : 
    1300             : 
    1301             : /**************************************************************************************/
    1302             : /*************************** IN: wkb - OUT: wkb - FLAG:int ****************************/
    1303             : /**************************************************************************************/
    1304             : 
    1305             : static str
    1306           5 : WKBtoWKBflagINT_bat(bat *outBAT_id, bat *inBAT_id, const int *flag, str (*func) (wkb **, wkb **, const int *), const char *name)
    1307             : {
    1308           5 :         BAT *outBAT = NULL, *inBAT = NULL;
    1309           5 :         wkb *inWKB = NULL;
    1310           5 :         BUN p = 0, q = 0;
    1311           5 :         BATiter inBAT_iter;
    1312             : 
    1313             :         //get the descriptor of the BAT
    1314           5 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1315           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1316             :         }
    1317             : 
    1318             :         //create a new for the output BAT
    1319           5 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1320           0 :                 BBPunfix(inBAT->batCacheid);
    1321           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1322             :         }
    1323             : 
    1324             :         //iterator over the input BAT
    1325           5 :         inBAT_iter = bat_iterator(inBAT);
    1326          13 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1327           8 :                 str err = NULL;
    1328           8 :                 wkb *outSingle;
    1329             : 
    1330           8 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1331           8 :                 if ((err = (*func) (&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1332           0 :                         bat_iterator_end(&inBAT_iter);
    1333           0 :                         BBPunfix(inBAT->batCacheid);
    1334           0 :                         BBPunfix(outBAT->batCacheid);
    1335           0 :                         return err;
    1336             :                 }
    1337           8 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1338           0 :                         bat_iterator_end(&inBAT_iter);
    1339           0 :                         BBPunfix(inBAT->batCacheid);
    1340           0 :                         BBPunfix(outBAT->batCacheid);
    1341           0 :                         GDKfree(outSingle);
    1342           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1343             :                 }
    1344           8 :                 GDKfree(outSingle);
    1345           8 :                 outSingle = NULL;
    1346             :         }
    1347           5 :         bat_iterator_end(&inBAT_iter);
    1348             : 
    1349             :         //set the number of elements in the outBAT
    1350           5 :         BATsetcount(outBAT, BATcount(inBAT));
    1351             : 
    1352           5 :         BBPunfix(inBAT->batCacheid);
    1353           5 :         *outBAT_id = outBAT->batCacheid;
    1354           5 :         BBPkeepref(outBAT);
    1355             : 
    1356           5 :         return MAL_SUCCEED;
    1357             : }
    1358             : 
    1359             : str
    1360           5 : wkbGeometryN_bat(bat *outBAT_id, bat *inBAT_id, const int *flag)
    1361             : {
    1362           5 :         return WKBtoWKBflagINT_bat(outBAT_id, inBAT_id, flag, wkbGeometryN, "batgeom.wkbGeometryN");
    1363             : }
    1364             : 
    1365             : /***************************************************************************/
    1366             : /*************************** IN: wkb - OUT: bit ****************************/
    1367             : /***************************************************************************/
    1368             : 
    1369             : static str
    1370          29 : WKBtoBIT_bat(bat *outBAT_id, bat *inBAT_id, str (*func) (bit *, wkb **), const char *name)
    1371             : {
    1372          29 :         BAT *outBAT = NULL, *inBAT = NULL;
    1373          29 :         wkb *inWKB = NULL;
    1374          29 :         BUN p = 0, q = 0;
    1375          29 :         BATiter inBAT_iter;
    1376             : 
    1377             :         //get the descriptor of the BAT
    1378          29 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1379           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1380             :         }
    1381             : 
    1382             :         //create a new for the output BAT
    1383          29 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("bit"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1384           0 :                 BBPunfix(inBAT->batCacheid);
    1385           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1386             :         }
    1387             : 
    1388             :         //iterator over the input BAT
    1389          29 :         inBAT_iter = bat_iterator(inBAT);
    1390         117 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1391          88 :                 str err = NULL;
    1392          88 :                 bit outSingle;
    1393             : 
    1394          88 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1395          88 :                 if ((err = (*func) (&outSingle, &inWKB)) != MAL_SUCCEED) {
    1396           0 :                         bat_iterator_end(&inBAT_iter);
    1397           0 :                         BBPunfix(inBAT->batCacheid);
    1398           0 :                         BBPunfix(outBAT->batCacheid);
    1399           0 :                         return err;
    1400             :                 }
    1401          88 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1402           0 :                         bat_iterator_end(&inBAT_iter);
    1403           0 :                         BBPunfix(inBAT->batCacheid);
    1404           0 :                         BBPunfix(outBAT->batCacheid);
    1405           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1406             :                 }
    1407             :         }
    1408          29 :         bat_iterator_end(&inBAT_iter);
    1409             : 
    1410             :         //set the number of elements in the outBAT
    1411          29 :         BATsetcount(outBAT, BATcount(inBAT));
    1412             : 
    1413          29 :         BBPunfix(inBAT->batCacheid);
    1414          29 :         *outBAT_id = outBAT->batCacheid;
    1415          29 :         BBPkeepref(outBAT);
    1416             : 
    1417          29 :         return MAL_SUCCEED;
    1418             : 
    1419             : }
    1420             : 
    1421             : str
    1422           7 : wkbIsClosed_bat(bat *outBAT_id, bat *inBAT_id)
    1423             : {
    1424           7 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsClosed, "batgeom.wkbIsClosed");
    1425             : }
    1426             : 
    1427             : str
    1428           5 : wkbIsEmpty_bat(bat *outBAT_id, bat *inBAT_id)
    1429             : {
    1430           5 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsEmpty, "batgeom.wkbIsEmpty");
    1431             : }
    1432             : 
    1433             : str
    1434           7 : wkbIsSimple_bat(bat *outBAT_id, bat *inBAT_id)
    1435             : {
    1436           7 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsSimple, "batgeom.wkbIsSimple");
    1437             : }
    1438             : 
    1439             : str
    1440           4 : wkbIsRing_bat(bat *outBAT_id, bat *inBAT_id)
    1441             : {
    1442           4 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsRing, "batgeom.wkbIsRing");
    1443             : }
    1444             : 
    1445             : str
    1446           6 : wkbIsValid_bat(bat *outBAT_id, bat *inBAT_id)
    1447             : {
    1448           6 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsValid, "batgeom.wkbIsValid");
    1449             : }
    1450             : 
    1451             : 
    1452             : /***************************************************************************/
    1453             : /*************************** IN: wkb - OUT: int ****************************/
    1454             : /***************************************************************************/
    1455             : 
    1456             : static str
    1457          10 : WKBtoINT_bat(bat *outBAT_id, bat *inBAT_id, str (*func) (int *, wkb **), const char *name)
    1458             : {
    1459          10 :         BAT *outBAT = NULL, *inBAT = NULL;
    1460          10 :         wkb *inWKB = NULL;
    1461          10 :         BUN p = 0, q = 0;
    1462          10 :         BATiter inBAT_iter;
    1463             : 
    1464             :         //get the descriptor of the BAT
    1465          10 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1466           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1467             :         }
    1468             : 
    1469             :         //create a new for the output BAT
    1470          10 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("int"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1471           0 :                 BBPunfix(inBAT->batCacheid);
    1472           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1473             :         }
    1474             : 
    1475             :         //iterator over the input BAT
    1476          10 :         inBAT_iter = bat_iterator(inBAT);
    1477          46 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1478          36 :                 str err = NULL;
    1479          36 :                 int outSingle;
    1480             : 
    1481          36 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1482          36 :                 if ((err = (*func) (&outSingle, &inWKB)) != MAL_SUCCEED) {
    1483           0 :                         bat_iterator_end(&inBAT_iter);
    1484           0 :                         BBPunfix(inBAT->batCacheid);
    1485           0 :                         BBPunfix(outBAT->batCacheid);
    1486           0 :                         return err;
    1487             :                 }
    1488          36 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1489           0 :                         bat_iterator_end(&inBAT_iter);
    1490           0 :                         BBPunfix(inBAT->batCacheid);
    1491           0 :                         BBPunfix(outBAT->batCacheid);
    1492           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1493             :                 }
    1494             :         }
    1495          10 :         bat_iterator_end(&inBAT_iter);
    1496             : 
    1497             :         //set the number of elements in the outBAT
    1498          10 :         BATsetcount(outBAT, BATcount(inBAT));
    1499             : 
    1500          10 :         BBPunfix(inBAT->batCacheid);
    1501          10 :         *outBAT_id = outBAT->batCacheid;
    1502          10 :         BBPkeepref(outBAT);
    1503             : 
    1504          10 :         return MAL_SUCCEED;
    1505             : 
    1506             : }
    1507             : 
    1508             : str
    1509           5 : wkbDimension_bat(bat *outBAT_id, bat *inBAT_id)
    1510             : {
    1511           5 :         return WKBtoINT_bat(outBAT_id, inBAT_id, wkbDimension, "batgeom.wkbDimension");
    1512             : }
    1513             : 
    1514             : str
    1515           5 : wkbNumGeometries_bat(bat *outBAT_id, bat *inBAT_id)
    1516             : {
    1517           5 :         return WKBtoINT_bat(outBAT_id, inBAT_id, wkbNumGeometries, "batgeom.wkbNumGeometries");
    1518             : }
    1519             : 
    1520             : /***************************************************************************************/
    1521             : /*************************** IN: wkb - OUT: int - FLAG: int ****************************/
    1522             : /***************************************************************************************/
    1523             : 
    1524             : static str
    1525          18 : WKBtoINTflagINT_bat(bat *outBAT_id, bat *inBAT_id, int *flag, str (*func) (int *, wkb **, int *), const char *name)
    1526             : {
    1527          18 :         BAT *outBAT = NULL, *inBAT = NULL;
    1528          18 :         wkb *inWKB = NULL;
    1529          18 :         BUN p = 0, q = 0;
    1530          18 :         BATiter inBAT_iter;
    1531             : 
    1532             :         //get the descriptor of the BAT
    1533          18 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1534           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1535             :         }
    1536             : 
    1537             :         //create a new for the output BAT
    1538          18 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("int"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1539           0 :                 BBPunfix(inBAT->batCacheid);
    1540           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1541             :         }
    1542             : 
    1543             :         //iterator over the input BAT
    1544          18 :         inBAT_iter = bat_iterator(inBAT);
    1545          52 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1546          34 :                 str err = NULL;
    1547          34 :                 int outSingle;
    1548             : 
    1549          34 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1550          34 :                 if ((err = (*func) (&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1551           0 :                         bat_iterator_end(&inBAT_iter);
    1552           0 :                         BBPunfix(inBAT->batCacheid);
    1553           0 :                         BBPunfix(outBAT->batCacheid);
    1554           0 :                         return err;
    1555             :                 }
    1556          34 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1557           0 :                         bat_iterator_end(&inBAT_iter);
    1558           0 :                         BBPunfix(inBAT->batCacheid);
    1559           0 :                         BBPunfix(outBAT->batCacheid);
    1560           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1561             :                 }
    1562             :         }
    1563          18 :         bat_iterator_end(&inBAT_iter);
    1564             : 
    1565             :         //set the number of elements in the outBAT
    1566          18 :         BATsetcount(outBAT, BATcount(inBAT));
    1567             : 
    1568          18 :         BBPunfix(inBAT->batCacheid);
    1569          18 :         *outBAT_id = outBAT->batCacheid;
    1570          18 :         BBPkeepref(outBAT);
    1571             : 
    1572          18 :         return MAL_SUCCEED;
    1573             : 
    1574             : }
    1575             : 
    1576             : str
    1577           9 : wkbNumPoints_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1578             : {
    1579           9 :         return WKBtoINTflagINT_bat(outBAT_id, inBAT_id, flag, wkbNumPoints, "batgeom.wkbNumPoints");
    1580             : }
    1581             : 
    1582             : str
    1583           9 : wkbNumRings_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1584             : {
    1585           9 :         return WKBtoINTflagINT_bat(outBAT_id, inBAT_id, flag, wkbNumRings, "batgeom.wkbNumRings");
    1586             : }
    1587             : 
    1588             : /******************************************************************************************/
    1589             : /*************************** IN: wkb - OUT: double - FLAG: int ****************************/
    1590             : /******************************************************************************************/
    1591             : 
    1592             : str
    1593          10 : wkbGetCoordinate_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1594             : {
    1595          10 :         BAT *outBAT = NULL, *inBAT = NULL;
    1596          10 :         wkb *inWKB = NULL;
    1597          10 :         BUN p = 0, q = 0;
    1598          10 :         BATiter inBAT_iter;
    1599             : 
    1600             :         //get the descriptor of the BAT
    1601          10 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1602           0 :                 throw(MAL, "batgeom.wkbGetCoordinate", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1603             :         }
    1604             : 
    1605             :         //create a new for the output BAT
    1606          10 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("dbl"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1607           0 :                 BBPunfix(inBAT->batCacheid);
    1608           0 :                 throw(MAL, "batgeom.wkbGetCoordinate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1609             :         }
    1610             : 
    1611             :         //iterator over the input BAT
    1612          10 :         inBAT_iter = bat_iterator(inBAT);
    1613          28 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1614          20 :                 str err = NULL;
    1615          20 :                 double outSingle;
    1616             : 
    1617          20 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1618          20 :                 if ((err = wkbGetCoordinate(&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1619           2 :                         bat_iterator_end(&inBAT_iter);
    1620           2 :                         BBPunfix(inBAT->batCacheid);
    1621           2 :                         BBPunfix(outBAT->batCacheid);
    1622           2 :                         return err;
    1623             :                 }
    1624          18 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1625           0 :                         bat_iterator_end(&inBAT_iter);
    1626           0 :                         BBPunfix(inBAT->batCacheid);
    1627           0 :                         BBPunfix(outBAT->batCacheid);
    1628           0 :                         throw(MAL, "batgeom.wkbGetCoordinate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1629             :                 }
    1630             :         }
    1631           8 :         bat_iterator_end(&inBAT_iter);
    1632             : 
    1633             :         //set the number of elements in the outBAT
    1634           8 :         BATsetcount(outBAT, BATcount(inBAT));
    1635             : 
    1636           8 :         BBPunfix(inBAT->batCacheid);
    1637           8 :         *outBAT_id = outBAT->batCacheid;
    1638           8 :         BBPkeepref(outBAT);
    1639             : 
    1640           8 :         return MAL_SUCCEED;
    1641             : 
    1642             : }
    1643             : 
    1644             : /*******************************/
    1645             : /********* Two inputs **********/
    1646             : /*******************************/
    1647             : 
    1648             : str
    1649           4 : wkbBox2D_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    1650             : {
    1651           4 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    1652           4 :         BATiter aBAT_iter, bBAT_iter;
    1653           4 :         BUN i = 0;
    1654           4 :         str ret = MAL_SUCCEED;
    1655             : 
    1656             :         //get the BATs
    1657           4 :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL || (bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    1658           0 :                 ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1659           0 :                 goto clean;
    1660             :         }
    1661             :         //check if the BATs are aligned
    1662           4 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    1663           0 :                 ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(38000) "Columns must be aligned");
    1664           0 :                 goto clean;
    1665             :         }
    1666             :         //create a new BAT for the output
    1667           4 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("mbr"), BATcount(aBAT), TRANSIENT)) == NULL) {
    1668           0 :                 ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1669           0 :                 goto clean;
    1670             :         }
    1671             : 
    1672             :         //iterator over the BATs
    1673           4 :         aBAT_iter = bat_iterator(aBAT);
    1674           4 :         bBAT_iter = bat_iterator(bBAT);
    1675             : 
    1676          24 :         for (i = 0; i < BATcount(aBAT); i++) {
    1677          16 :                 mbr *outSingle;
    1678             : 
    1679          16 :                 wkb *aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    1680          16 :                 wkb *bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    1681             : 
    1682          16 :                 if ((ret = wkbBox2D(&outSingle, &aWKB, &bWKB)) != MAL_SUCCEED) {
    1683           0 :                         BBPreclaim(outBAT);
    1684           0 :                         goto bailout;
    1685             :                 }
    1686          16 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1687           0 :                         BBPreclaim(outBAT);
    1688           0 :                         GDKfree(outSingle);
    1689           0 :                         ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1690           0 :                         goto bailout;
    1691             :                 }
    1692          16 :                 GDKfree(outSingle);
    1693             :         }
    1694             : 
    1695           4 :         *outBAT_id = outBAT->batCacheid;
    1696           4 :         BBPkeepref(outBAT);
    1697           4 :   bailout:
    1698           4 :         bat_iterator_end(&aBAT_iter);
    1699           4 :         bat_iterator_end(&bBAT_iter);
    1700             : 
    1701           4 :   clean:
    1702           4 :         BBPreclaim(aBAT);
    1703           4 :         BBPreclaim(bBAT);
    1704             : 
    1705           4 :         return ret;
    1706             : }
    1707             : 
    1708             : str
    1709           6 : wkbContains_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    1710             : {
    1711           6 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    1712           6 :         BATiter aBAT_iter, bBAT_iter;
    1713           6 :         BUN i = 0;
    1714           6 :         str ret = MAL_SUCCEED;
    1715             : 
    1716             :         //get the BATs
    1717           6 :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL || (bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    1718           0 :                 ret = createException(MAL, "batgeom.Contains", SQLSTATE(38000) "Problem retrieving BATs");
    1719           0 :                 goto clean;
    1720             :         }
    1721             :         //check if the BATs are aligned
    1722           6 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    1723           0 :                 ret = createException(MAL, "batgeom.Contains", SQLSTATE(38000) "Columns must be aligned");
    1724           0 :                 goto clean;
    1725             :         }
    1726             :         //create a new BAT for the output
    1727           6 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("bit"), BATcount(aBAT), TRANSIENT)) == NULL) {
    1728           0 :                 ret = createException(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1729           0 :                 goto clean;
    1730             :         }
    1731             : 
    1732             :         //iterator over the BATs
    1733           6 :         aBAT_iter = bat_iterator(aBAT);
    1734           6 :         bBAT_iter = bat_iterator(bBAT);
    1735             : 
    1736          17 :         for (i = 0; i < BATcount(aBAT); i++) {
    1737           5 :                 bit outBIT;
    1738             : 
    1739           5 :                 wkb *aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    1740           5 :                 wkb *bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    1741             : 
    1742           5 :                 if ((ret = wkbContains(&outBIT, &aWKB, &bWKB)) != MAL_SUCCEED) {
    1743           0 :                         BBPreclaim(outBAT);
    1744           0 :                         goto bailout;
    1745             :                 }
    1746           5 :                 if (BUNappend(outBAT, &outBIT, false) != GDK_SUCCEED) {
    1747           0 :                         BBPreclaim(outBAT);
    1748           0 :                         ret = createException(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1749           0 :                         goto bailout;
    1750             :                 }
    1751             :         }
    1752             : 
    1753           6 :         *outBAT_id = outBAT->batCacheid;
    1754           6 :         BBPkeepref(outBAT);
    1755             : 
    1756           6 :   bailout:
    1757           6 :         bat_iterator_end(&aBAT_iter);
    1758           6 :         bat_iterator_end(&bBAT_iter);
    1759             : 
    1760           6 :   clean:
    1761           6 :         BBPreclaim(aBAT);
    1762           6 :         BBPreclaim(bBAT);
    1763             : 
    1764           6 :         return ret;
    1765             : }
    1766             : 
    1767             : str
    1768           0 : wkbContains_geom_bat(bat *outBAT_id, wkb **geomWKB, bat *inBAT_id)
    1769             : {
    1770           0 :         BAT *outBAT = NULL, *inBAT = NULL;
    1771           0 :         BATiter inBAT_iter;
    1772           0 :         BUN p = 0, q = 0;
    1773             : 
    1774             :         //get the descriptor of the BAT
    1775           0 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1776           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1777             :         }
    1778             : 
    1779             :         //create a new BAT for the output
    1780           0 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("bit"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1781           0 :                 BBPunfix(inBAT->batCacheid);
    1782           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1783             :         }
    1784             : 
    1785             :         //iterator over the BATs
    1786           0 :         inBAT_iter = bat_iterator(inBAT);
    1787           0 :         BATloop(inBAT, p, q) {
    1788           0 :                 str err = NULL;
    1789           0 :                 bit outBIT;
    1790             : 
    1791           0 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1792             : 
    1793           0 :                 if ((err = wkbContains(&outBIT, geomWKB, &inWKB)) != MAL_SUCCEED) {
    1794           0 :                         bat_iterator_end(&inBAT_iter);
    1795           0 :                         BBPunfix(inBAT->batCacheid);
    1796           0 :                         BBPunfix(outBAT->batCacheid);
    1797           0 :                         return err;
    1798             :                 }
    1799           0 :                 if (BUNappend(outBAT, &outBIT, false) != GDK_SUCCEED) {
    1800           0 :                         bat_iterator_end(&inBAT_iter);
    1801           0 :                         BBPunfix(inBAT->batCacheid);
    1802           0 :                         BBPunfix(outBAT->batCacheid);
    1803           0 :                         throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1804             :                 }
    1805             :         }
    1806           0 :         bat_iterator_end(&inBAT_iter);
    1807             : 
    1808           0 :         BBPunfix(inBAT->batCacheid);
    1809           0 :         *outBAT_id = outBAT->batCacheid;
    1810           0 :         BBPkeepref(outBAT);
    1811             : 
    1812           0 :         return MAL_SUCCEED;
    1813             : 
    1814             : }
    1815             : 
    1816             : str
    1817           8 : wkbContains_bat_geom(bat *outBAT_id, bat *inBAT_id, wkb **geomWKB)
    1818             : {
    1819           8 :         BAT *outBAT = NULL, *inBAT = NULL;
    1820           8 :         BATiter inBAT_iter;
    1821           8 :         BUN p = 0, q = 0;
    1822             : 
    1823             :         //get the descriptor of the BAT
    1824           8 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1825           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1826             :         }
    1827             : 
    1828             :         //create a new BAT for the output
    1829           8 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("bit"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1830           0 :                 BBPunfix(inBAT->batCacheid);
    1831           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1832             :         }
    1833             : 
    1834             :         //iterator over the BATs
    1835           8 :         inBAT_iter = bat_iterator(inBAT);
    1836          26 :         BATloop(inBAT, p, q) {
    1837          18 :                 str err = NULL;
    1838          18 :                 bit outBIT;
    1839             : 
    1840          18 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1841             : 
    1842          18 :                 if ((err = wkbContains(&outBIT, &inWKB, geomWKB)) != MAL_SUCCEED) {
    1843           0 :                         bat_iterator_end(&inBAT_iter);
    1844           0 :                         BBPunfix(inBAT->batCacheid);
    1845           0 :                         BBPunfix(outBAT->batCacheid);
    1846           0 :                         return err;
    1847             :                 }
    1848          18 :                 if (BUNappend(outBAT, &outBIT, false) != GDK_SUCCEED) {
    1849           0 :                         bat_iterator_end(&inBAT_iter);
    1850           0 :                         BBPunfix(inBAT->batCacheid);
    1851           0 :                         BBPunfix(outBAT->batCacheid);
    1852           0 :                         throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1853             :                 }
    1854             :         }
    1855           8 :         bat_iterator_end(&inBAT_iter);
    1856             : 
    1857           8 :         BBPunfix(inBAT->batCacheid);
    1858           8 :         *outBAT_id = outBAT->batCacheid;
    1859           8 :         BBPkeepref(outBAT);
    1860             : 
    1861           8 :         return MAL_SUCCEED;
    1862             : }
    1863             : 
    1864             : 
    1865             : 
    1866             : /*
    1867             : str
    1868             : wkbFromWKB_bat(bat *outBAT_id, bat *inBAT_id)
    1869             : {
    1870             :         BAT *outBAT = NULL, *inBAT = NULL;
    1871             :         wkb **inWKB = NULL, *outWKB = NULL;
    1872             :         BUN i;
    1873             : 
    1874             :         //get the descriptor of the BAT
    1875             :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1876             :                 throw(MAL, "batgeom.wkb", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1877             :         }
    1878             : 
    1879             :         //create a new BAT
    1880             :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT))) == NULL) {
    1881             :                 BBPunfix(inBAT->batCacheid);
    1882             :                 throw(MAL, "batgeom.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1883             :         }
    1884             : 
    1885             :         //pointers to the first valid elements of the x and y BATS
    1886             :         BATiter inBATi = bat_iterator(inBAT);
    1887             :         inWKB = (wkb **) inBATi.base;
    1888             :         for (i = 0; i < BATcount(inBAT); i++) {      //iterate over all valid elements
    1889             :                 str err = NULL;
    1890             :                 if ((err = wkbFromWKB(&outWKB, &inWKB[i])) != MAL_SUCCEED) {
    1891             :                         BBPunfix(inBAT->batCacheid);
    1892             :                         BBPunfix(outBAT->batCacheid);
    1893             :                         return err;
    1894             :                 }
    1895             :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    1896             :                         BBPunfix(inBAT->batCacheid);
    1897             :                         BBPunfix(outBAT->batCacheid);
    1898             :                         GDKfree(outWKB);
    1899             :                         throw(MAL, "batgeom.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1900             :                 }
    1901             :                 GDKfree(outWKB);
    1902             :                 outWKB = NULL;
    1903             :         }
    1904             :         bat_iterator_end(&inBATi);
    1905             : 
    1906             :         BBPunfix(inBAT->batCacheid);
    1907             :         *outBAT_id = outBAT->batCacheid;
    1908             :         BBPkeepref(outBAT);
    1909             :         return MAL_SUCCEED;
    1910             : 
    1911             : }
    1912             : */
    1913             : 
    1914             : /************************************/
    1915             : /********* Multiple inputs **********/
    1916             : /************************************/
    1917             : str
    1918           5 : wkbMakePoint_bat(bat *outBAT_id, bat *xBAT_id, bat *yBAT_id, bat *zBAT_id, bat *mBAT_id, int *zmFlag)
    1919             : {
    1920           5 :         BAT *outBAT = NULL, *xBAT = NULL, *yBAT = NULL, *zBAT = NULL, *mBAT = NULL;
    1921           5 :         BATiter xBAT_iter, yBAT_iter, zBAT_iter, mBAT_iter;
    1922           5 :         BUN i;
    1923           5 :         str ret = MAL_SUCCEED;
    1924             : 
    1925           5 :         if (*zmFlag == 11)
    1926           1 :                 throw(MAL, "batgeom.wkbMakePoint", SQLSTATE(38000) "POINTZM is not supported");
    1927             : 
    1928             :         //get the BATs
    1929           4 :         if ((xBAT = BATdescriptor(*xBAT_id)) == NULL || (yBAT = BATdescriptor(*yBAT_id)) == NULL || (*zmFlag == 10 && (zBAT = BATdescriptor(*zBAT_id)) == NULL)
    1930           4 :             || (*zmFlag == 1 && (mBAT = BATdescriptor(*mBAT_id)) == NULL)) {
    1931             : 
    1932           0 :                 ret = createException(MAL, "batgeom.wkbMakePoint", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1933           0 :                 goto clean;
    1934             :         }
    1935             :         //check if the BATs are aligned
    1936           4 :         if (xBAT->hseqbase != yBAT->hseqbase ||
    1937           4 :             BATcount(xBAT) != BATcount(yBAT) ||
    1938           4 :             (zBAT && (xBAT->hseqbase != zBAT->hseqbase || BATcount(xBAT) != BATcount(zBAT))) ||
    1939           1 :             (mBAT && (xBAT->hseqbase != mBAT->hseqbase || BATcount(xBAT) != BATcount(mBAT)))) {
    1940           0 :                 ret = createException(MAL, "batgeom.wkbMakePoint", SQLSTATE(38000) "Columns must be aligned");
    1941           0 :                 goto clean;
    1942             :         }
    1943             :         //create a new BAT for the output
    1944           4 :         if ((outBAT = COLnew(xBAT->hseqbase, ATOMindex("wkb"), BATcount(xBAT), TRANSIENT)) == NULL) {
    1945           0 :                 ret = createException(MAL, "batgeom.wkbMakePoint", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1946           0 :                 goto clean;
    1947             :         }
    1948             : 
    1949             :         //iterator over the BATs
    1950           4 :         xBAT_iter = bat_iterator(xBAT);
    1951           4 :         yBAT_iter = bat_iterator(yBAT);
    1952           4 :         if (zBAT)
    1953           1 :                 zBAT_iter = bat_iterator(zBAT);
    1954           4 :         if (mBAT)
    1955           1 :                 mBAT_iter = bat_iterator(mBAT);
    1956             : 
    1957          16 :         for (i = 0; i < BATcount(xBAT); i++) {
    1958          12 :                 wkb *pointWKB = NULL;
    1959             : 
    1960          12 :                 double x = *((double *) BUNtloc(xBAT_iter, i));
    1961          12 :                 double y = *((double *) BUNtloc(yBAT_iter, i));
    1962          12 :                 double z = 0.0;
    1963          12 :                 double m = 0.0;
    1964             : 
    1965          12 :                 if (zBAT)
    1966           3 :                         z = *((double *) BUNtloc(zBAT_iter, i));
    1967          12 :                 if (mBAT)
    1968           3 :                         m = *((double *) BUNtloc(mBAT_iter, i));
    1969             : 
    1970          12 :                 if ((ret = wkbMakePoint(&pointWKB, &x, &y, &z, &m, zmFlag)) != MAL_SUCCEED) {       //check
    1971             : 
    1972           0 :                         BBPreclaim(outBAT);
    1973           0 :                         goto bailout;
    1974             :                 }
    1975          12 :                 if (BUNappend(outBAT, pointWKB, false) != GDK_SUCCEED) {
    1976           0 :                         BBPreclaim(outBAT);
    1977           0 :                         GDKfree(pointWKB);
    1978           0 :                         ret = createException(MAL, "batgeom.WkbMakePoint", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1979           0 :                         goto bailout;
    1980             :                 }
    1981          12 :                 GDKfree(pointWKB);
    1982             :         }
    1983             : 
    1984           4 :         *outBAT_id = outBAT->batCacheid;
    1985           4 :         BBPkeepref(outBAT);
    1986             : 
    1987           4 :   bailout:
    1988           4 :         bat_iterator_end(&xBAT_iter);
    1989           4 :         bat_iterator_end(&yBAT_iter);
    1990           4 :         if (zBAT)
    1991           1 :                 bat_iterator_end(&zBAT_iter);
    1992           4 :         if (mBAT)
    1993           1 :                 bat_iterator_end(&mBAT_iter);
    1994           3 :   clean:
    1995           4 :         BBPreclaim(xBAT);
    1996           4 :         BBPreclaim(yBAT);
    1997           4 :         BBPreclaim(zBAT);
    1998           4 :         BBPreclaim(mBAT);
    1999             : 
    2000             :         return ret;
    2001             : }
    2002             : 
    2003             : 
    2004             : /* sets the srid of the geometry - BULK version*/
    2005             : str
    2006           0 : wkbSetSRID_bat(bat *outBAT_id, bat *inBAT_id, int *srid)
    2007             : {
    2008           0 :         BAT *outBAT = NULL, *inBAT = NULL;
    2009           0 :         BUN p = 0, q = 0;
    2010           0 :         BATiter inBAT_iter;
    2011             : 
    2012             :         //get the descriptor of the BAT
    2013           0 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    2014           0 :                 throw(MAL, "batgeom.SetSRID", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2015             :         }
    2016             : 
    2017             :         //create a new BAT for the output
    2018           0 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT), TRANSIENT)) == NULL) {
    2019           0 :                 BBPunfix(inBAT->batCacheid);
    2020           0 :                 throw(MAL, "batgeom.SetSRID", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2021             :         }
    2022             : 
    2023             :         //iterator over the BATs
    2024           0 :         inBAT_iter = bat_iterator(inBAT);
    2025           0 :         BATloop(inBAT, p, q) {
    2026           0 :                 str err = NULL;
    2027           0 :                 wkb *outWKB = NULL;
    2028             : 
    2029           0 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    2030             : 
    2031           0 :                 if ((err = wkbSetSRID(&outWKB, &inWKB, srid)) != MAL_SUCCEED) { //set SRID
    2032           0 :                         bat_iterator_end(&inBAT_iter);
    2033           0 :                         BBPunfix(inBAT->batCacheid);
    2034           0 :                         BBPunfix(outBAT->batCacheid);
    2035           0 :                         return err;
    2036             :                 }
    2037           0 :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    2038           0 :                         bat_iterator_end(&inBAT_iter);
    2039           0 :                         BBPunfix(inBAT->batCacheid);
    2040           0 :                         BBPunfix(outBAT->batCacheid);
    2041           0 :                         GDKfree(outWKB);
    2042           0 :                         throw(MAL, "batgeom.SetSRID", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2043             :                 }
    2044           0 :                 GDKfree(outWKB);
    2045           0 :                 outWKB = NULL;
    2046             :         }
    2047           0 :         bat_iterator_end(&inBAT_iter);
    2048             : 
    2049           0 :         BBPunfix(inBAT->batCacheid);
    2050           0 :         *outBAT_id = outBAT->batCacheid;
    2051           0 :         BBPkeepref(outBAT);
    2052             : 
    2053           0 :         return MAL_SUCCEED;
    2054             : }
    2055             : 
    2056             : str
    2057           2 : wkbDistance_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    2058             : {
    2059           2 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    2060           2 :         BATiter aBAT_iter, bBAT_iter;
    2061           2 :         BUN i = 0;
    2062           2 :         str ret = MAL_SUCCEED;
    2063             : 
    2064             :         //get the BATs
    2065           2 :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL || (bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    2066           0 :                 ret = createException(MAL, "batgeom.Distance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2067           0 :                 goto clean;
    2068             :         }
    2069             :         //check if the BATs are aligned
    2070           2 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    2071           0 :                 ret = createException(MAL, "batgeom.Distance", SQLSTATE(38000) "Columns must be aligned");
    2072           0 :                 goto clean;
    2073             :         }
    2074             :         //create a new BAT for the output
    2075           2 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("dbl"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2076           0 :                 ret = createException(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2077           0 :                 goto clean;
    2078             :         }
    2079             : 
    2080             :         //iterator over the BATs
    2081           2 :         aBAT_iter = bat_iterator(aBAT);
    2082           2 :         bBAT_iter = bat_iterator(bBAT);
    2083             : 
    2084           5 :         for (i = 0; i < BATcount(aBAT); i++) {
    2085           1 :                 double distanceVal = 0;
    2086             : 
    2087           1 :                 wkb *aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2088           1 :                 wkb *bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2089             : 
    2090           1 :                 if ((ret = wkbDistance(&distanceVal, &aWKB, &bWKB)) != MAL_SUCCEED) {       //check
    2091             : 
    2092           0 :                         BBPreclaim(outBAT);
    2093           0 :                         goto bailout;
    2094             :                 }
    2095           1 :                 if (BUNappend(outBAT, &distanceVal, false) != GDK_SUCCEED) {
    2096           0 :                         BBPreclaim(outBAT);
    2097           0 :                         ret = createException(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2098           0 :                         goto bailout;
    2099             :                 }
    2100             :         }
    2101             : 
    2102           2 :         *outBAT_id = outBAT->batCacheid;
    2103           2 :         BBPkeepref(outBAT);
    2104             : 
    2105           2 :   bailout:
    2106           2 :         bat_iterator_end(&aBAT_iter);
    2107           2 :         bat_iterator_end(&bBAT_iter);
    2108           2 :   clean:
    2109           2 :         BBPreclaim(aBAT);
    2110           2 :         BBPreclaim(bBAT);
    2111             : 
    2112           2 :         return ret;
    2113             : 
    2114             : }
    2115             : 
    2116             : str
    2117           0 : wkbDistance_geom_bat(bat *outBAT_id, wkb **geomWKB, bat *inBAT_id)
    2118             : {
    2119           0 :         BAT *outBAT = NULL, *inBAT = NULL;
    2120           0 :         BATiter inBAT_iter;
    2121           0 :         BUN p = 0, q = 0;
    2122             : 
    2123             :         //get the descriptor of the BAT
    2124           0 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    2125           0 :                 throw(MAL, "batgeom.Distance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2126             :         }
    2127             : 
    2128             :         //create a new BAT for the output
    2129           0 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("dbl"), BATcount(inBAT), TRANSIENT)) == NULL) {
    2130           0 :                 BBPunfix(inBAT->batCacheid);
    2131           0 :                 throw(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2132             :         }
    2133             : 
    2134             :         //iterator over the BAT
    2135           0 :         inBAT_iter = bat_iterator(inBAT);
    2136           0 :         BATloop(inBAT, p, q) {
    2137           0 :                 str err = NULL;
    2138           0 :                 double distanceVal = 0;
    2139             : 
    2140           0 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    2141             : 
    2142           0 :                 if ((err = wkbDistance(&distanceVal, geomWKB, &inWKB)) != MAL_SUCCEED) {        //check
    2143           0 :                         bat_iterator_end(&inBAT_iter);
    2144           0 :                         BBPunfix(inBAT->batCacheid);
    2145           0 :                         BBPunfix(outBAT->batCacheid);
    2146           0 :                         return err;
    2147             :                 }
    2148           0 :                 if (BUNappend(outBAT, &distanceVal, false) != GDK_SUCCEED) {
    2149           0 :                         bat_iterator_end(&inBAT_iter);
    2150           0 :                         BBPunfix(inBAT->batCacheid);
    2151           0 :                         BBPunfix(outBAT->batCacheid);
    2152           0 :                         throw(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2153             :                 }
    2154             :         }
    2155           0 :         bat_iterator_end(&inBAT_iter);
    2156             : 
    2157           0 :         BBPunfix(inBAT->batCacheid);
    2158           0 :         *outBAT_id = outBAT->batCacheid;
    2159           0 :         BBPkeepref(outBAT);
    2160             : 
    2161           0 :         return MAL_SUCCEED;
    2162             : }
    2163             : 
    2164             : str
    2165           0 : wkbDistance_bat_geom(bat *outBAT_id, bat *inBAT_id, wkb **geomWKB)
    2166             : {
    2167           0 :         return wkbDistance_geom_bat(outBAT_id, geomWKB, inBAT_id);
    2168             : }
    2169             : 
    2170             : /**
    2171             :  * It filters the geometry in the second BAT with respect to the MBR of the geometry in the first BAT.
    2172             :  **/
    2173             : /*
    2174             : str
    2175             : wkbFilter_bat(bat *aBATfiltered_id, bat *bBATfiltered_id, bat *aBAT_id, bat *bBAT_id)
    2176             : {
    2177             :         BAT *aBATfiltered = NULL, *bBATfiltered = NULL, *aBAT = NULL, *bBAT = NULL;
    2178             :         wkb *aWKB = NULL, *bWKB = NULL;
    2179             :         bit outBIT;
    2180             :         BATiter aBAT_iter, bBAT_iter;
    2181             :         BUN i = 0;
    2182             : 
    2183             :         //get the descriptor of the BAT
    2184             :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL) {
    2185             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2186             :         }
    2187             :         if ((bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    2188             :                 BBPunfix(aBAT->batCacheid);
    2189             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2190             :         }
    2191             : 
    2192             :         if (aBAT->hseqbase != bBAT->hseqbase ||   //the idxs of the headers of the BATs are not the same
    2193             :             BATcount(aBAT) != BATcount(bBAT)) { //the number of valid elements in the BATs are not the same
    2194             :                 BBPunfix(aBAT->batCacheid);
    2195             :                 BBPunfix(bBAT->batCacheid);
    2196             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(38000) "The arguments must have dense and aligned heads");
    2197             :         }
    2198             :         //create two new BATs for the output
    2199             :         if ((aBATfiltered = COLnew(aBAT->hseqbase, ATOMindex("wkb"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2200             :                 BBPunfix(aBAT->batCacheid);
    2201             :                 BBPunfix(bBAT->batCacheid);
    2202             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2203             :         }
    2204             :         if ((bBATfiltered = COLnew(bBAT->hseqbase, ATOMindex("wkb"), BATcount(bBAT), TRANSIENT)) == NULL) {
    2205             :                 BBPunfix(aBAT->batCacheid);
    2206             :                 BBPunfix(bBAT->batCacheid);
    2207             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2208             :         }
    2209             : 
    2210             :         //iterator over the BATs
    2211             :         aBAT_iter = bat_iterator(aBAT);
    2212             :         bBAT_iter = bat_iterator(bBAT);
    2213             : 
    2214             :         for (i = 0; i < BATcount(aBAT); i++) {
    2215             :                 str err = NULL;
    2216             :                 aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2217             :                 bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2218             : 
    2219             :                 //check the containment of the MBRs
    2220             :                 if ((err = mbrOverlaps_wkb(&outBIT, &aWKB, &bWKB)) != MAL_SUCCEED) {
    2221             :                         bat_iterator_end(&aBAT_iter);
    2222             :                         bat_iterator_end(&bBAT_iter);
    2223             :                         BBPunfix(aBAT->batCacheid);
    2224             :                         BBPunfix(bBAT->batCacheid);
    2225             :                         BBPunfix(aBATfiltered->batCacheid);
    2226             :                         BBPunfix(bBATfiltered->batCacheid);
    2227             :                         return err;
    2228             :                 }
    2229             :                 if (outBIT) {
    2230             :                         if (BUNappend(aBATfiltered, aWKB, false) != GDK_SUCCEED ||
    2231             :                             BUNappend(bBATfiltered, bWKB, false) != GDK_SUCCEED) {
    2232             :                                 bat_iterator_end(&aBAT_iter);
    2233             :                                 bat_iterator_end(&bBAT_iter);
    2234             :                                 BBPunfix(aBAT->batCacheid);
    2235             :                                 BBPunfix(bBAT->batCacheid);
    2236             :                                 BBPunfix(aBATfiltered->batCacheid);
    2237             :                                 BBPunfix(bBATfiltered->batCacheid);
    2238             :                                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2239             :                         }
    2240             :                 }
    2241             :         }
    2242             :         bat_iterator_end(&aBAT_iter);
    2243             :         bat_iterator_end(&bBAT_iter);
    2244             : 
    2245             :         BBPunfix(aBAT->batCacheid);
    2246             :         BBPunfix(bBAT->batCacheid);
    2247             :         *aBATfiltered_id = aBATfiltered->batCacheid;
    2248             :         BBPkeepref(aBATfiltered);
    2249             :         *bBATfiltered_id = bBATfiltered->batCacheid;
    2250             :         BBPkeepref(bBATfiltered);
    2251             : 
    2252             :         return MAL_SUCCEED;
    2253             : 
    2254             : 
    2255             : }
    2256             : */
    2257             : 
    2258             : /**
    2259             :  * It filters the geometry in the second BAT with respect to the MBR of the geometry in the first BAT.
    2260             :  **/
    2261             : str
    2262           0 : wkbFilter_geom_bat(bat *BATfiltered_id, wkb **geomWKB, bat *BAToriginal_id)
    2263             : {
    2264           0 :         BAT *BATfiltered = NULL, *BAToriginal = NULL;
    2265           0 :         wkb *WKBoriginal = NULL;
    2266           0 :         BATiter BAToriginal_iter;
    2267           0 :         BUN i = 0;
    2268           0 :         mbr *geomMBR;
    2269           0 :         str err = NULL;
    2270             : 
    2271             :         //get the descriptor of the BAT
    2272           0 :         if ((BAToriginal = BATdescriptor(*BAToriginal_id)) == NULL) {
    2273           0 :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2274             :         }
    2275             : 
    2276             :         //create the new BAT
    2277           0 :         if ((BATfiltered = COLnew(BAToriginal->hseqbase, ATOMindex("wkb"), BATcount(BAToriginal), TRANSIENT)) == NULL) {
    2278           0 :                 BBPunfix(BAToriginal->batCacheid);
    2279           0 :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2280             :         }
    2281             : 
    2282             :         //create the MBR of the geom
    2283           0 :         if ((err = wkbMBR(&geomMBR, geomWKB)) != MAL_SUCCEED) {
    2284           0 :                 BBPunfix(BAToriginal->batCacheid);
    2285           0 :                 BBPunfix(BATfiltered->batCacheid);
    2286           0 :                 return err;
    2287             :         }
    2288             : 
    2289             :         //iterator over the BAT
    2290           0 :         BAToriginal_iter = bat_iterator(BAToriginal);
    2291             : 
    2292           0 :         for (i = 0; i < BATcount(BAToriginal); i++) {
    2293           0 :                 str err = NULL;
    2294           0 :                 mbr *MBRoriginal;
    2295           0 :                 bit outBIT = 0;
    2296             : 
    2297           0 :                 WKBoriginal = (wkb *) BUNtvar(BAToriginal_iter, i);
    2298             : 
    2299             :                 //create the MBR for each geometry in the BAT
    2300           0 :                 if ((err = wkbMBR(&MBRoriginal, &WKBoriginal)) != MAL_SUCCEED) {
    2301           0 :                         bat_iterator_end(&BAToriginal_iter);
    2302           0 :                         BBPunfix(BAToriginal->batCacheid);
    2303           0 :                         BBPunfix(BATfiltered->batCacheid);
    2304           0 :                         GDKfree(geomMBR);
    2305           0 :                         return err;
    2306             :                 }
    2307             :                 //check the containment of the MBRs
    2308           0 :                 if ((err = mbrOverlaps(&outBIT, &geomMBR, &MBRoriginal)) != MAL_SUCCEED) {
    2309           0 :                         bat_iterator_end(&BAToriginal_iter);
    2310           0 :                         BBPunfix(BAToriginal->batCacheid);
    2311           0 :                         BBPunfix(BATfiltered->batCacheid);
    2312           0 :                         GDKfree(geomMBR);
    2313           0 :                         GDKfree(MBRoriginal);
    2314           0 :                         return err;
    2315             :                 }
    2316             : 
    2317           0 :                 if (outBIT) {
    2318           0 :                         if (BUNappend(BATfiltered, WKBoriginal, false) != GDK_SUCCEED) {
    2319           0 :                                 bat_iterator_end(&BAToriginal_iter);
    2320           0 :                                 BBPunfix(BAToriginal->batCacheid);
    2321           0 :                                 BBPunfix(BATfiltered->batCacheid);
    2322           0 :                                 GDKfree(geomMBR);
    2323           0 :                                 GDKfree(MBRoriginal);
    2324           0 :                                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2325             :                         }
    2326             :                 }
    2327             : 
    2328           0 :                 GDKfree(MBRoriginal);
    2329             :         }
    2330           0 :         bat_iterator_end(&BAToriginal_iter);
    2331             : 
    2332           0 :         GDKfree(geomMBR);
    2333           0 :         BBPunfix(BAToriginal->batCacheid);
    2334           0 :         *BATfiltered_id = BATfiltered->batCacheid;
    2335           0 :         BBPkeepref(BATfiltered);
    2336             : 
    2337           0 :         return MAL_SUCCEED;
    2338             : 
    2339             : }
    2340             : 
    2341             : str
    2342           0 : wkbFilter_bat_geom(bat *BATfiltered_id, bat *BAToriginal_id, wkb **geomWKB)
    2343             : {
    2344           0 :         return wkbFilter_geom_bat(BATfiltered_id, geomWKB, BAToriginal_id);
    2345             : }
    2346             : 
    2347             : /* MBR */
    2348             : str
    2349           4 : wkbCoordinateFromWKB_bat(bat *outBAT_id, bat *inBAT_id, int *coordinateIdx)
    2350             : {
    2351           4 :         str err = NULL;
    2352           4 :         bat inBAT_mbr_id = 0;   //the id of the bat with the mbrs
    2353             : 
    2354           4 :         if ((err = wkbMBR_bat(&inBAT_mbr_id, inBAT_id)) != MAL_SUCCEED) {
    2355             :                 return err;
    2356             :         }
    2357             :         //call the bulk version of wkbCoordinateFromMBR
    2358           4 :         err = wkbCoordinateFromMBR_bat(outBAT_id, &inBAT_mbr_id, coordinateIdx);
    2359           4 :         BBPrelease(inBAT_mbr_id);
    2360           4 :         return err;
    2361             : }
    2362             : 
    2363             : str
    2364           1 : wkbMakeLine_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    2365             : {
    2366           1 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    2367           1 :         BATiter aBAT_iter, bBAT_iter;
    2368           1 :         BUN i;
    2369             : 
    2370             :         //get the BATs
    2371           1 :         aBAT = BATdescriptor(*aBAT_id);
    2372           1 :         bBAT = BATdescriptor(*bBAT_id);
    2373           1 :         if (aBAT == NULL || bBAT == NULL) {
    2374           0 :                 BBPreclaim(aBAT);
    2375           0 :                 BBPreclaim(bBAT);
    2376           0 :                 throw(MAL, "batgeom.MakeLine", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2377             :         }
    2378             :         //check if the BATs are aligned
    2379           1 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    2380           0 :                 BBPunfix(aBAT->batCacheid);
    2381           0 :                 BBPunfix(bBAT->batCacheid);
    2382           0 :                 throw(MAL, "batgeom.MakeLine", SQLSTATE(38000) "Columns must be aligned");
    2383             :         }
    2384             :         //create a new BAT for the output
    2385           1 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("wkb"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2386           0 :                 BBPunfix(aBAT->batCacheid);
    2387           0 :                 BBPunfix(bBAT->batCacheid);
    2388           0 :                 throw(MAL, "batgeom.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2389             :         }
    2390             : 
    2391             :         //iterator over the BATs
    2392           1 :         aBAT_iter = bat_iterator(aBAT);
    2393           1 :         bBAT_iter = bat_iterator(bBAT);
    2394             : 
    2395           4 :         for (i = 0; i < BATcount(aBAT); i++) {
    2396           2 :                 str err = NULL;
    2397           2 :                 wkb *aWKB = NULL, *bWKB = NULL, *outWKB = NULL;
    2398             : 
    2399           2 :                 aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2400           2 :                 bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2401             : 
    2402           2 :                 if ((err = wkbMakeLine(&outWKB, &aWKB, &bWKB)) != MAL_SUCCEED) {    //check
    2403           0 :                         bat_iterator_end(&aBAT_iter);
    2404           0 :                         bat_iterator_end(&bBAT_iter);
    2405           0 :                         BBPunfix(outBAT->batCacheid);
    2406           0 :                         BBPunfix(aBAT->batCacheid);
    2407           0 :                         BBPunfix(bBAT->batCacheid);
    2408           0 :                         return err;
    2409             :                 }
    2410           2 :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    2411           0 :                         bat_iterator_end(&aBAT_iter);
    2412           0 :                         bat_iterator_end(&bBAT_iter);
    2413           0 :                         BBPunfix(outBAT->batCacheid);
    2414           0 :                         BBPunfix(aBAT->batCacheid);
    2415           0 :                         BBPunfix(bBAT->batCacheid);
    2416           0 :                         GDKfree(outWKB);
    2417           0 :                         throw(MAL, "batgeom.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2418             :                 }
    2419           2 :                 GDKfree(outWKB);
    2420           2 :                 outWKB = NULL;
    2421             :         }
    2422           1 :         bat_iterator_end(&aBAT_iter);
    2423           1 :         bat_iterator_end(&bBAT_iter);
    2424             : 
    2425           1 :         *outBAT_id = outBAT->batCacheid;
    2426           1 :         BBPkeepref(outBAT);
    2427           1 :         BBPunfix(aBAT->batCacheid);
    2428           1 :         BBPunfix(bBAT->batCacheid);
    2429             : 
    2430           1 :         return MAL_SUCCEED;
    2431             : }
    2432             : 
    2433             : str
    2434           2 : wkbUnion_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    2435             : {
    2436           2 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    2437           2 :         BATiter aBAT_iter, bBAT_iter;
    2438           2 :         BUN i;
    2439             : 
    2440             :         //get the BATs
    2441           2 :         aBAT = BATdescriptor(*aBAT_id);
    2442           2 :         bBAT = BATdescriptor(*bBAT_id);
    2443           2 :         if (aBAT == NULL || bBAT == NULL) {
    2444           0 :                 BBPreclaim(aBAT);
    2445           0 :                 BBPreclaim(bBAT);
    2446           0 :                 throw(MAL, "batgeom.Union", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2447             :         }
    2448             :         //check if the BATs are aligned
    2449           2 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    2450           0 :                 BBPunfix(aBAT->batCacheid);
    2451           0 :                 BBPunfix(bBAT->batCacheid);
    2452           0 :                 throw(MAL, "batgeom.Union", SQLSTATE(38000) "Columns must be aligned");
    2453             :         }
    2454             :         //create a new BAT for the output
    2455           2 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("wkb"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2456           0 :                 BBPunfix(aBAT->batCacheid);
    2457           0 :                 BBPunfix(bBAT->batCacheid);
    2458           0 :                 throw(MAL, "batgeom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2459             :         }
    2460             : 
    2461             :         //iterator over the BATs
    2462           2 :         aBAT_iter = bat_iterator(aBAT);
    2463           2 :         bBAT_iter = bat_iterator(bBAT);
    2464             : 
    2465           5 :         for (i = 0; i < BATcount(aBAT); i++) {
    2466           1 :                 str err = NULL;
    2467           1 :                 wkb *aWKB = NULL, *bWKB = NULL, *outWKB = NULL;
    2468             : 
    2469           1 :                 aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2470           1 :                 bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2471             : 
    2472           1 :                 if ((err = wkbUnion(&outWKB, &aWKB, &bWKB)) != MAL_SUCCEED) {       //check
    2473           0 :                         bat_iterator_end(&aBAT_iter);
    2474           0 :                         bat_iterator_end(&bBAT_iter);
    2475           0 :                         BBPunfix(outBAT->batCacheid);
    2476           0 :                         BBPunfix(aBAT->batCacheid);
    2477           0 :                         BBPunfix(bBAT->batCacheid);
    2478           0 :                         return err;
    2479             :                 }
    2480           1 :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    2481           0 :                         bat_iterator_end(&aBAT_iter);
    2482           0 :                         bat_iterator_end(&bBAT_iter);
    2483           0 :                         BBPunfix(outBAT->batCacheid);
    2484           0 :                         BBPunfix(aBAT->batCacheid);
    2485           0 :                         BBPunfix(bBAT->batCacheid);
    2486           0 :                         GDKfree(outWKB);
    2487           0 :                         throw(MAL, "batgeom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2488             :                 }
    2489           1 :                 GDKfree(outWKB);
    2490           1 :                 outWKB = NULL;
    2491             :         }
    2492           2 :         bat_iterator_end(&aBAT_iter);
    2493           2 :         bat_iterator_end(&bBAT_iter);
    2494             : 
    2495           2 :         *outBAT_id = outBAT->batCacheid;
    2496           2 :         BBPkeepref(outBAT);
    2497           2 :         BBPunfix(aBAT->batCacheid);
    2498           2 :         BBPunfix(bBAT->batCacheid);
    2499             : 
    2500           2 :         return MAL_SUCCEED;
    2501             : }

Generated by: LCOV version 1.14