LCOV - code coverage report
Current view: top level - geom/monetdb5 - geomBulk.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 497 1209 41.1 %
Date: 2024-10-04 20:04:04 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, 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(*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(*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, 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(*l_id) && RTREEexists_bid(*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(*l_id) && RTREEexists_bid(*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 :                                 err = createException(MAL, "batgeom.Transform", SQLSTATE(38000) "Geos operation geos2wkb failed");
     827             :                         else {
     828           0 :                                 if (BUNappend(outBAT, transformedWKB, false) != GDK_SUCCEED) {
     829           0 :                                         err = createException(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 :         if (err) {
     846           0 :                 BBPreclaim(outBAT);
     847             :         } else {
     848           0 :                 *outBAT_id = outBAT->batCacheid;
     849           0 :                 BBPkeepref(outBAT);
     850             :         }
     851             : 
     852             :         return err;
     853             : #endif
     854             : }
     855             : 
     856             : /* ST_DistanceGeographic Bulk function */
     857             : str
     858           0 : wkbDistanceGeographic_bat(bat *out_id, const bat *a_id, const bat *b_id)
     859             : {
     860           0 :         return wkbDistanceGeographic_bat_cand(out_id,a_id,b_id,NULL,NULL);
     861             : }
     862             : 
     863             : str
     864           0 : wkbDistanceGeographic_bat_cand(bat *out_id, const bat *a_id, const bat *b_id, const bat *s1_id, const bat *s2_id)
     865             : {
     866           0 :         BAT *out = NULL, *a = NULL, *b = NULL, *s1 = NULL, *s2 = NULL;
     867           0 :         BATiter a_iter, b_iter;
     868           0 :         str msg = MAL_SUCCEED;
     869           0 :         struct canditer ci1, ci2;
     870             : 
     871             :         //get the BATs
     872           0 :         if ((a = BATdescriptor(*a_id)) == NULL || (b = BATdescriptor(*b_id)) == NULL) {
     873           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     874           0 :                 goto clean;
     875             :         }
     876             :         //check if the BATs are aligned
     877           0 :         if (a->hseqbase != b->hseqbase || BATcount(a) != BATcount(b)) {
     878           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(38000) "Columns must be aligned");
     879           0 :                 goto clean;
     880             :         }
     881             :         //check for candidate lists
     882           0 :         if (s1_id && !is_bat_nil(*s1_id) && (s1 = BATdescriptor(*s1_id)) == NULL) {
     883           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     884           0 :                 goto clean;
     885             :         }
     886           0 :         if (s2_id && !is_bat_nil(*s2_id) && (s2 = BATdescriptor(*s2_id)) == NULL) {
     887           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     888           0 :                 if (s1)
     889           0 :                         BBPunfix(s1->batCacheid);
     890           0 :                 goto clean;
     891             :         }
     892           0 :         canditer_init(&ci1, a, s1);
     893           0 :         canditer_init(&ci2, b, s2);
     894             : 
     895             :         //create a new BAT for the output
     896           0 :         if ((out = COLnew(0, ATOMindex("dbl"), ci1.ncand, TRANSIENT)) == NULL) {
     897           0 :                 msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     898           0 :                 if (s1)
     899           0 :                         BBPunfix(s1->batCacheid);
     900           0 :                 if (s2)
     901           0 :                         BBPunfix(s2->batCacheid);
     902           0 :                 goto clean;
     903             :         }
     904             :         //iterator over the BATs
     905           0 :         a_iter = bat_iterator(a);
     906           0 :         b_iter = bat_iterator(b);
     907             : 
     908           0 :         for (BUN i = 0; i < ci1.ncand; i++) {
     909           0 :                 double distanceVal = 0;
     910           0 :                 oid p1 = (canditer_next(&ci1) - a->hseqbase);
     911           0 :                 oid p2 = (canditer_next(&ci2) - b->hseqbase);
     912           0 :                 wkb *aWKB = (wkb *) BUNtvar(a_iter, p1);
     913           0 :                 wkb *bWKB = (wkb *) BUNtvar(b_iter, p2);
     914             : 
     915           0 :                 if ((msg = wkbDistanceGeographic(&distanceVal, &aWKB, &bWKB)) != MAL_SUCCEED) {
     916           0 :                         BBPreclaim(out);
     917           0 :                         goto bailout;
     918             :                 }
     919           0 :                 if (BUNappend(out, &distanceVal, false) != GDK_SUCCEED) {
     920           0 :                         BBPreclaim(out);
     921           0 :                         msg = createException(MAL, "batgeom.DistanceGeographic", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     922           0 :                         goto bailout;
     923             :                 }
     924             :         }
     925           0 :         *out_id = out->batCacheid;
     926           0 :         BBPkeepref(out);
     927           0 : bailout:
     928           0 :         bat_iterator_end(&a_iter);
     929           0 :         bat_iterator_end(&b_iter);
     930           0 :         BBPreclaim(s1);
     931           0 :         BBPreclaim(s2);
     932           0 : clean:
     933           0 :         BBPreclaim(a);
     934           0 :         BBPreclaim(b);
     935           0 :         BBPreclaim(out);
     936           0 :         return msg;
     937             : }
     938             : 
     939             : /********** Geo Update End **********/
     940             : 
     941             : /*******************************/
     942             : /********** One input **********/
     943             : /*******************************/
     944             : 
     945             : str
     946           1 : geom_2_geom_bat(bat *outBAT_id, bat *inBAT_id, bat *cand, int *columnType, int *columnSRID)
     947             : {
     948           1 :         BAT *b = NULL, *s = NULL, *dst = NULL;
     949           1 :         BATiter bi;
     950           1 :         str msg = MAL_SUCCEED;
     951           1 :         struct canditer ci;
     952           1 :         oid off = 0;
     953           1 :         bool nils = false;
     954           1 :         wkb *inWKB = NULL, *outWKB = NULL;
     955             : 
     956             :         //get the descriptor of the BAT
     957           1 :         if ((b = BATdescriptor(*inBAT_id)) == NULL) {
     958           0 :                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     959           0 :                 goto bailout;
     960             :         }
     961           1 :         bi = bat_iterator(b);
     962           1 :         if (cand && !is_bat_nil(*cand) && (s = BATdescriptor(*cand)) == NULL) {
     963           0 :                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     964           0 :                 goto bailout;
     965             :         }
     966           1 :         off = b->hseqbase;
     967           1 :         canditer_init(&ci, b, s);
     968             :         //create a new BAT, aligned with input BAT
     969           1 :         if ((dst = COLnew(ci.hseq, ATOMindex("wkb"), ci.ncand, TRANSIENT)) == NULL) {
     970           0 :                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     971           0 :                 goto bailout;
     972             :         }
     973             : 
     974           1 :         if (ci.tpe == cand_dense) {
     975           4 :                 for (BUN i = 0; i < ci.ncand; i++) {
     976           3 :                         oid p = (canditer_next_dense(&ci) - off);
     977           3 :                         inWKB = (wkb *) BUNtvar(bi, p);
     978             : 
     979           3 :                         if ((msg = geom_2_geom(&outWKB, &inWKB, columnType, columnSRID)) != MAL_SUCCEED)        //check type
     980           0 :                                 goto bailout;
     981           3 :                         if (tfastins_nocheckVAR(dst, i, outWKB) != GDK_SUCCEED) {
     982           0 :                                 GDKfree(outWKB);
     983           0 :                                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     984           0 :                                 goto bailout;
     985             :                         }
     986           3 :                         nils |= is_wkb_nil(outWKB);
     987           3 :                         GDKfree(outWKB);
     988           3 :                         outWKB = NULL;
     989             :                 }
     990             :         } else {
     991           0 :                 for (BUN i = 0; i < ci.ncand; i++) {
     992           0 :                         oid p = (canditer_next(&ci) - off);
     993           0 :                         inWKB = (wkb *) BUNtvar(bi, p);
     994             : 
     995           0 :                         if ((msg = geom_2_geom(&outWKB, &inWKB, columnType, columnSRID)) != MAL_SUCCEED)        //check type
     996           0 :                                 goto bailout;
     997           0 :                         if (tfastins_nocheckVAR(dst, i, outWKB) != GDK_SUCCEED) {
     998           0 :                                 GDKfree(outWKB);
     999           0 :                                 msg = createException(MAL, "batcalc.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1000           0 :                                 goto bailout;
    1001             :                         }
    1002           0 :                         nils |= is_wkb_nil(outWKB);
    1003           0 :                         GDKfree(outWKB);
    1004           0 :                         outWKB = NULL;
    1005             :                 }
    1006             :         }
    1007             : 
    1008           0 : bailout:
    1009           1 :         if (b) {
    1010           1 :                 bat_iterator_end(&bi);
    1011           1 :                 BBPunfix(b->batCacheid);
    1012             :         }
    1013           1 :         BBPreclaim(s);
    1014           1 :         if (dst && !msg) {
    1015           1 :                 BATsetcount(dst, ci.ncand);
    1016           1 :                 dst->tnil = nils;
    1017           1 :                 dst->tnonil = !nils;
    1018           1 :                 dst->tkey = BATcount(dst) <= 1;
    1019           1 :                 dst->tsorted = BATcount(dst) <= 1;
    1020           1 :                 dst->trevsorted = BATcount(dst) <= 1;
    1021           1 :                 *outBAT_id = dst->batCacheid;
    1022           1 :                 BBPkeepref(dst);
    1023           0 :         } else if (dst)
    1024           0 :                 BBPreclaim(dst);
    1025           1 :         return msg;
    1026             : }
    1027             : 
    1028             : /*create WKB from WKT */
    1029             : str
    1030          49 : wkbFromText_bat(bat *outBAT_id, bat *inBAT_id, int *srid, int *tpe)
    1031             : {
    1032          49 :         return wkbFromText_bat_cand(outBAT_id, inBAT_id, NULL, srid, tpe);
    1033             : }
    1034             : 
    1035             : str
    1036          53 : wkbFromText_bat_cand(bat *outBAT_id, bat *inBAT_id, bat *cand, int *srid, int *tpe)
    1037             : {
    1038          53 :         BAT *b = NULL, *s = NULL, *dst = NULL;
    1039          53 :         BATiter bi;
    1040          53 :         str msg = MAL_SUCCEED;
    1041          53 :         struct canditer ci;
    1042          53 :         oid off = 0;
    1043          53 :         bool nils = false;
    1044             : 
    1045             :         //get the descriptor of the BAT
    1046          53 :         if ((b = BATdescriptor(*inBAT_id)) == NULL) {
    1047           0 :                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1048           0 :                 goto bailout;
    1049             :         }
    1050          53 :         bi = bat_iterator(b);
    1051          53 :         if (cand && !is_bat_nil(*cand) && (s = BATdescriptor(*cand)) == NULL) {
    1052           0 :                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1053           0 :                 goto bailout;
    1054             :         }
    1055          53 :         off = b->hseqbase;
    1056          53 :         canditer_init(&ci, b, s);
    1057             :         //create a new BAT, aligned with input BAT
    1058          53 :         if ((dst = COLnew(ci.hseq, ATOMindex("wkb"), ci.ncand, TRANSIENT)) == NULL) {
    1059           0 :                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1060           0 :                 goto bailout;
    1061             :         }
    1062             : 
    1063          53 :         if (ci.tpe == cand_dense) {
    1064          78 :                 for (BUN i = 0; i < ci.ncand; i++) {
    1065          68 :                         oid p = (canditer_next_dense(&ci) - off);
    1066          68 :                         str inWKB = (str) BUNtvar(bi, p);
    1067          68 :                         wkb *outSingle;
    1068             : 
    1069          68 :                         if ((msg = wkbFromText(&outSingle, &inWKB, srid, tpe)) != MAL_SUCCEED)
    1070          43 :                                 goto bailout;
    1071          25 :                         if (tfastins_nocheckVAR(dst, i, outSingle) != GDK_SUCCEED) {
    1072           0 :                                 GDKfree(outSingle);
    1073           0 :                                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1074           0 :                                 goto bailout;
    1075             :                         }
    1076          25 :                         nils |= is_wkb_nil(outSingle);
    1077          25 :                         GDKfree(outSingle);
    1078          25 :                         outSingle = NULL;
    1079             :                 }
    1080             :         } else {
    1081           0 :                 for (BUN i = 0; i < ci.ncand; i++) {
    1082           0 :                         oid p = (canditer_next(&ci) - off);
    1083           0 :                         str inWKB = (str) BUNtvar(bi, p);
    1084           0 :                         wkb *outSingle;
    1085             : 
    1086           0 :                         if ((msg = wkbFromText(&outSingle, &inWKB, srid, tpe)) != MAL_SUCCEED)
    1087           0 :                                 goto bailout;
    1088           0 :                         if (tfastins_nocheckVAR(dst, i, outSingle) != GDK_SUCCEED) {
    1089           0 :                                 GDKfree(outSingle);
    1090           0 :                                 msg = createException(MAL, "batgeom.wkbFromText", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1091           0 :                                 goto bailout;
    1092             :                         }
    1093           0 :                         nils |= is_wkb_nil(outSingle);
    1094           0 :                         GDKfree(outSingle);
    1095           0 :                         outSingle = NULL;
    1096             :                 }
    1097             :         }
    1098             : 
    1099           0 : bailout:
    1100          53 :         if (b) {
    1101          53 :                 bat_iterator_end(&bi);
    1102          53 :                 BBPunfix(b->batCacheid);
    1103             :         }
    1104          53 :         BBPreclaim(s);
    1105          53 :         if (dst && !msg) {
    1106          10 :                 BATsetcount(dst, ci.ncand);
    1107          10 :                 dst->tnil = nils;
    1108          10 :                 dst->tnonil = !nils;
    1109          10 :                 dst->tkey = BATcount(dst) <= 1;
    1110          10 :                 dst->tsorted = BATcount(dst) <= 1;
    1111          10 :                 dst->trevsorted = BATcount(dst) <= 1;
    1112          10 :                 *outBAT_id = dst->batCacheid;
    1113          10 :                 BBPkeepref(dst);
    1114          43 :         } else if (dst)
    1115          43 :                 BBPreclaim(dst);
    1116          53 :         return msg;
    1117             : }
    1118             : 
    1119             : /*****************************************************************************/
    1120             : /********************* IN: mbr - OUT: double - FLAG :int *********************/
    1121             : /*****************************************************************************/
    1122             : str
    1123           8 : wkbCoordinateFromMBR_bat(bat *outBAT_id, bat *inBAT_id, int *coordinateIdx)
    1124             : {
    1125           8 :         BAT *outBAT = NULL, *inBAT = NULL;
    1126           8 :         mbr *inMBR = NULL;
    1127           8 :         double outDbl = 0.0;
    1128           8 :         BUN p = 0, q = 0;
    1129           8 :         BATiter inBAT_iter;
    1130             : 
    1131             :         //get the descriptor of the BAT
    1132           8 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1133           0 :                 throw(MAL, "batgeom.coordinateFromMBR", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1134             :         }
    1135             : 
    1136             :         //create a new BAT for the output
    1137           8 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("dbl"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1138           0 :                 BBPunfix(inBAT->batCacheid);
    1139           0 :                 throw(MAL, "batgeom.coordinateFromMBR", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1140             :         }
    1141             : 
    1142             :         //iterator over the BAT
    1143           8 :         inBAT_iter = bat_iterator(inBAT);
    1144         224 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1145         216 :                 str err = NULL;
    1146             : 
    1147         216 :                 inMBR = (mbr *) BUNtloc(inBAT_iter, p);
    1148         216 :                 if ((err = wkbCoordinateFromMBR(&outDbl, &inMBR, coordinateIdx)) != MAL_SUCCEED) {
    1149           0 :                         bat_iterator_end(&inBAT_iter);
    1150           0 :                         BBPunfix(inBAT->batCacheid);
    1151           0 :                         BBPunfix(outBAT->batCacheid);
    1152           0 :                         return err;
    1153             :                 }
    1154         216 :                 if (BUNappend(outBAT, &outDbl, false) != GDK_SUCCEED) {
    1155           0 :                         bat_iterator_end(&inBAT_iter);
    1156           0 :                         BBPunfix(inBAT->batCacheid);
    1157           0 :                         BBPunfix(outBAT->batCacheid);
    1158           0 :                         throw(MAL, "batgeom.coordinateFromMBR", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1159             :                 }
    1160             :         }
    1161           8 :         bat_iterator_end(&inBAT_iter);
    1162             : 
    1163           8 :         BBPunfix(inBAT->batCacheid);
    1164           8 :         *outBAT_id = outBAT->batCacheid;
    1165           8 :         BBPkeepref(outBAT);
    1166           8 :         return MAL_SUCCEED;
    1167             : 
    1168             : }
    1169             : 
    1170             : /**************************************************************************/
    1171             : /********************* IN: wkb - OUT: str - FLAG :int *********************/
    1172             : /**************************************************************************/
    1173             : static str
    1174          45 : WKBtoSTRflagINT_bat(bat *outBAT_id, bat *inBAT_id, int *flag, str (*func) (char **, wkb **, int *), const char *name)
    1175             : {
    1176          45 :         BAT *outBAT = NULL, *inBAT = NULL;
    1177          45 :         wkb *inWKB = NULL;
    1178          45 :         BUN p = 0, q = 0;
    1179          45 :         BATiter inBAT_iter;
    1180             : 
    1181             :         //get the descriptor of the BAT
    1182          45 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1183           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1184             :         }
    1185             : 
    1186             :         //create a new for the output BAT
    1187          45 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("str"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1188           0 :                 BBPunfix(inBAT->batCacheid);
    1189           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1190             :         }
    1191             : 
    1192             :         //iterator over the input BAT
    1193          45 :         inBAT_iter = bat_iterator(inBAT);
    1194         127 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1195          82 :                 str err = NULL;
    1196          82 :                 char *outSingle;
    1197             : 
    1198          82 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1199          82 :                 if ((err = (*func) (&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1200           0 :                         bat_iterator_end(&inBAT_iter);
    1201           0 :                         BBPunfix(inBAT->batCacheid);
    1202           0 :                         BBPunfix(outBAT->batCacheid);
    1203           0 :                         return err;
    1204             :                 }
    1205          82 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1206           0 :                         bat_iterator_end(&inBAT_iter);
    1207           0 :                         BBPunfix(inBAT->batCacheid);
    1208           0 :                         BBPunfix(outBAT->batCacheid);
    1209           0 :                         GDKfree(outSingle);
    1210           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1211             :                 }
    1212          82 :                 GDKfree(outSingle);
    1213          82 :                 outSingle = NULL;
    1214             :         }
    1215          45 :         bat_iterator_end(&inBAT_iter);
    1216             : 
    1217             :         //set the number of elements in the outBAT
    1218          45 :         BATsetcount(outBAT, BATcount(inBAT));
    1219             : 
    1220          45 :         BBPunfix(inBAT->batCacheid);
    1221          45 :         *outBAT_id = outBAT->batCacheid;
    1222          45 :         BBPkeepref(outBAT);
    1223             : 
    1224          45 :         return MAL_SUCCEED;
    1225             : }
    1226             : 
    1227             : /*create textual representation of the wkb */
    1228             : str
    1229          32 : wkbAsText_bat(bat *outBAT_id, bat *inBAT_id, int *withSRID)
    1230             : {
    1231          32 :         return WKBtoSTRflagINT_bat(outBAT_id, inBAT_id, withSRID, wkbAsText, "batgeom.wkbAsText");
    1232             : }
    1233             : 
    1234             : str
    1235          13 : wkbGeometryType_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1236             : {
    1237          13 :         return WKBtoSTRflagINT_bat(outBAT_id, inBAT_id, flag, wkbGeometryType, "batgeom.wkbGeometryType");
    1238             : }
    1239             : 
    1240             : /***************************************************************************/
    1241             : /*************************** IN: wkb - OUT: wkb ****************************/
    1242             : /***************************************************************************/
    1243             : 
    1244             : static str
    1245           5 : WKBtoWKB_bat(bat *outBAT_id, bat *inBAT_id, str (*func) (wkb **, wkb **), const char *name)
    1246             : {
    1247           5 :         BAT *outBAT = NULL, *inBAT = NULL;
    1248           5 :         wkb *inWKB = NULL;
    1249           5 :         BUN p = 0, q = 0;
    1250           5 :         BATiter inBAT_iter;
    1251             : 
    1252             :         //get the descriptor of the BAT
    1253           5 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1254           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1255             :         }
    1256             : 
    1257             :         //create a new for the output BAT
    1258           5 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1259           0 :                 BBPunfix(inBAT->batCacheid);
    1260           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1261             :         }
    1262             : 
    1263             :         //iterator over the input BAT
    1264           5 :         inBAT_iter = bat_iterator(inBAT);
    1265          29 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1266          24 :                 str err = NULL;
    1267          24 :                 wkb *outSingle;
    1268             : 
    1269          24 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1270          24 :                 if ((err = (*func) (&outSingle, &inWKB)) != MAL_SUCCEED) {
    1271           0 :                         bat_iterator_end(&inBAT_iter);
    1272           0 :                         BBPunfix(inBAT->batCacheid);
    1273           0 :                         BBPunfix(outBAT->batCacheid);
    1274           0 :                         return err;
    1275             :                 }
    1276          24 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1277           0 :                         bat_iterator_end(&inBAT_iter);
    1278           0 :                         BBPunfix(inBAT->batCacheid);
    1279           0 :                         BBPunfix(outBAT->batCacheid);
    1280           0 :                         GDKfree(outSingle);
    1281           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1282             :                 }
    1283          24 :                 GDKfree(outSingle);
    1284          24 :                 outSingle = NULL;
    1285             :         }
    1286           5 :         bat_iterator_end(&inBAT_iter);
    1287             : 
    1288             :         //set the number of elements in the outBAT
    1289           5 :         BATsetcount(outBAT, BATcount(inBAT));
    1290             : 
    1291           5 :         BBPunfix(inBAT->batCacheid);
    1292           5 :         *outBAT_id = outBAT->batCacheid;
    1293           5 :         BBPkeepref(outBAT);
    1294             : 
    1295           5 :         return MAL_SUCCEED;
    1296             : }
    1297             : 
    1298             : str
    1299           5 : wkbBoundary_bat(bat *outBAT_id, bat *inBAT_id)
    1300             : {
    1301           5 :         return WKBtoWKB_bat(outBAT_id, inBAT_id, wkbBoundary, "batgeom.wkbBoundary");
    1302             : }
    1303             : 
    1304             : 
    1305             : /**************************************************************************************/
    1306             : /*************************** IN: wkb - OUT: wkb - FLAG:int ****************************/
    1307             : /**************************************************************************************/
    1308             : 
    1309             : static str
    1310           5 : WKBtoWKBflagINT_bat(bat *outBAT_id, bat *inBAT_id, const int *flag, str (*func) (wkb **, wkb **, const int *), const char *name)
    1311             : {
    1312           5 :         BAT *outBAT = NULL, *inBAT = NULL;
    1313           5 :         wkb *inWKB = NULL;
    1314           5 :         BUN p = 0, q = 0;
    1315           5 :         BATiter inBAT_iter;
    1316             : 
    1317             :         //get the descriptor of the BAT
    1318           5 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1319           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1320             :         }
    1321             : 
    1322             :         //create a new for the output BAT
    1323           5 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1324           0 :                 BBPunfix(inBAT->batCacheid);
    1325           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1326             :         }
    1327             : 
    1328             :         //iterator over the input BAT
    1329           5 :         inBAT_iter = bat_iterator(inBAT);
    1330          13 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1331           8 :                 str err = NULL;
    1332           8 :                 wkb *outSingle;
    1333             : 
    1334           8 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1335           8 :                 if ((err = (*func) (&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1336           0 :                         bat_iterator_end(&inBAT_iter);
    1337           0 :                         BBPunfix(inBAT->batCacheid);
    1338           0 :                         BBPunfix(outBAT->batCacheid);
    1339           0 :                         return err;
    1340             :                 }
    1341           8 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1342           0 :                         bat_iterator_end(&inBAT_iter);
    1343           0 :                         BBPunfix(inBAT->batCacheid);
    1344           0 :                         BBPunfix(outBAT->batCacheid);
    1345           0 :                         GDKfree(outSingle);
    1346           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1347             :                 }
    1348           8 :                 GDKfree(outSingle);
    1349           8 :                 outSingle = NULL;
    1350             :         }
    1351           5 :         bat_iterator_end(&inBAT_iter);
    1352             : 
    1353             :         //set the number of elements in the outBAT
    1354           5 :         BATsetcount(outBAT, BATcount(inBAT));
    1355             : 
    1356           5 :         BBPunfix(inBAT->batCacheid);
    1357           5 :         *outBAT_id = outBAT->batCacheid;
    1358           5 :         BBPkeepref(outBAT);
    1359             : 
    1360           5 :         return MAL_SUCCEED;
    1361             : }
    1362             : 
    1363             : str
    1364           5 : wkbGeometryN_bat(bat *outBAT_id, bat *inBAT_id, const int *flag)
    1365             : {
    1366           5 :         return WKBtoWKBflagINT_bat(outBAT_id, inBAT_id, flag, wkbGeometryN, "batgeom.wkbGeometryN");
    1367             : }
    1368             : 
    1369             : /***************************************************************************/
    1370             : /*************************** IN: wkb - OUT: bit ****************************/
    1371             : /***************************************************************************/
    1372             : 
    1373             : static str
    1374          29 : WKBtoBIT_bat(bat *outBAT_id, bat *inBAT_id, str (*func) (bit *, wkb **), const char *name)
    1375             : {
    1376          29 :         BAT *outBAT = NULL, *inBAT = NULL;
    1377          29 :         wkb *inWKB = NULL;
    1378          29 :         BUN p = 0, q = 0;
    1379          29 :         BATiter inBAT_iter;
    1380             : 
    1381             :         //get the descriptor of the BAT
    1382          29 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1383           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1384             :         }
    1385             : 
    1386             :         //create a new for the output BAT
    1387          29 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("bit"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1388           0 :                 BBPunfix(inBAT->batCacheid);
    1389           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1390             :         }
    1391             : 
    1392             :         //iterator over the input BAT
    1393          29 :         inBAT_iter = bat_iterator(inBAT);
    1394         117 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1395          88 :                 str err = NULL;
    1396          88 :                 bit outSingle;
    1397             : 
    1398          88 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1399          88 :                 if ((err = (*func) (&outSingle, &inWKB)) != MAL_SUCCEED) {
    1400           0 :                         bat_iterator_end(&inBAT_iter);
    1401           0 :                         BBPunfix(inBAT->batCacheid);
    1402           0 :                         BBPunfix(outBAT->batCacheid);
    1403           0 :                         return err;
    1404             :                 }
    1405          88 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1406           0 :                         bat_iterator_end(&inBAT_iter);
    1407           0 :                         BBPunfix(inBAT->batCacheid);
    1408           0 :                         BBPunfix(outBAT->batCacheid);
    1409           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1410             :                 }
    1411             :         }
    1412          29 :         bat_iterator_end(&inBAT_iter);
    1413             : 
    1414             :         //set the number of elements in the outBAT
    1415          29 :         BATsetcount(outBAT, BATcount(inBAT));
    1416             : 
    1417          29 :         BBPunfix(inBAT->batCacheid);
    1418          29 :         *outBAT_id = outBAT->batCacheid;
    1419          29 :         BBPkeepref(outBAT);
    1420             : 
    1421          29 :         return MAL_SUCCEED;
    1422             : 
    1423             : }
    1424             : 
    1425             : str
    1426           7 : wkbIsClosed_bat(bat *outBAT_id, bat *inBAT_id)
    1427             : {
    1428           7 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsClosed, "batgeom.wkbIsClosed");
    1429             : }
    1430             : 
    1431             : str
    1432           5 : wkbIsEmpty_bat(bat *outBAT_id, bat *inBAT_id)
    1433             : {
    1434           5 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsEmpty, "batgeom.wkbIsEmpty");
    1435             : }
    1436             : 
    1437             : str
    1438           7 : wkbIsSimple_bat(bat *outBAT_id, bat *inBAT_id)
    1439             : {
    1440           7 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsSimple, "batgeom.wkbIsSimple");
    1441             : }
    1442             : 
    1443             : str
    1444           4 : wkbIsRing_bat(bat *outBAT_id, bat *inBAT_id)
    1445             : {
    1446           4 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsRing, "batgeom.wkbIsRing");
    1447             : }
    1448             : 
    1449             : str
    1450           6 : wkbIsValid_bat(bat *outBAT_id, bat *inBAT_id)
    1451             : {
    1452           6 :         return WKBtoBIT_bat(outBAT_id, inBAT_id, wkbIsValid, "batgeom.wkbIsValid");
    1453             : }
    1454             : 
    1455             : 
    1456             : /***************************************************************************/
    1457             : /*************************** IN: wkb - OUT: int ****************************/
    1458             : /***************************************************************************/
    1459             : 
    1460             : static str
    1461          10 : WKBtoINT_bat(bat *outBAT_id, bat *inBAT_id, str (*func) (int *, wkb **), const char *name)
    1462             : {
    1463          10 :         BAT *outBAT = NULL, *inBAT = NULL;
    1464          10 :         wkb *inWKB = NULL;
    1465          10 :         BUN p = 0, q = 0;
    1466          10 :         BATiter inBAT_iter;
    1467             : 
    1468             :         //get the descriptor of the BAT
    1469          10 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1470           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1471             :         }
    1472             : 
    1473             :         //create a new for the output BAT
    1474          10 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("int"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1475           0 :                 BBPunfix(inBAT->batCacheid);
    1476           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1477             :         }
    1478             : 
    1479             :         //iterator over the input BAT
    1480          10 :         inBAT_iter = bat_iterator(inBAT);
    1481          46 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1482          36 :                 str err = NULL;
    1483          36 :                 int outSingle;
    1484             : 
    1485          36 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1486          36 :                 if ((err = (*func) (&outSingle, &inWKB)) != MAL_SUCCEED) {
    1487           0 :                         bat_iterator_end(&inBAT_iter);
    1488           0 :                         BBPunfix(inBAT->batCacheid);
    1489           0 :                         BBPunfix(outBAT->batCacheid);
    1490           0 :                         return err;
    1491             :                 }
    1492          36 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1493           0 :                         bat_iterator_end(&inBAT_iter);
    1494           0 :                         BBPunfix(inBAT->batCacheid);
    1495           0 :                         BBPunfix(outBAT->batCacheid);
    1496           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1497             :                 }
    1498             :         }
    1499          10 :         bat_iterator_end(&inBAT_iter);
    1500             : 
    1501             :         //set the number of elements in the outBAT
    1502          10 :         BATsetcount(outBAT, BATcount(inBAT));
    1503             : 
    1504          10 :         BBPunfix(inBAT->batCacheid);
    1505          10 :         *outBAT_id = outBAT->batCacheid;
    1506          10 :         BBPkeepref(outBAT);
    1507             : 
    1508          10 :         return MAL_SUCCEED;
    1509             : 
    1510             : }
    1511             : 
    1512             : str
    1513           5 : wkbDimension_bat(bat *outBAT_id, bat *inBAT_id)
    1514             : {
    1515           5 :         return WKBtoINT_bat(outBAT_id, inBAT_id, wkbDimension, "batgeom.wkbDimension");
    1516             : }
    1517             : 
    1518             : str
    1519           5 : wkbNumGeometries_bat(bat *outBAT_id, bat *inBAT_id)
    1520             : {
    1521           5 :         return WKBtoINT_bat(outBAT_id, inBAT_id, wkbNumGeometries, "batgeom.wkbNumGeometries");
    1522             : }
    1523             : 
    1524             : /***************************************************************************************/
    1525             : /*************************** IN: wkb - OUT: int - FLAG: int ****************************/
    1526             : /***************************************************************************************/
    1527             : 
    1528             : static str
    1529          18 : WKBtoINTflagINT_bat(bat *outBAT_id, bat *inBAT_id, int *flag, str (*func) (int *, wkb **, int *), const char *name)
    1530             : {
    1531          18 :         BAT *outBAT = NULL, *inBAT = NULL;
    1532          18 :         wkb *inWKB = NULL;
    1533          18 :         BUN p = 0, q = 0;
    1534          18 :         BATiter inBAT_iter;
    1535             : 
    1536             :         //get the descriptor of the BAT
    1537          18 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1538           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1539             :         }
    1540             : 
    1541             :         //create a new for the output BAT
    1542          18 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("int"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1543           0 :                 BBPunfix(inBAT->batCacheid);
    1544           0 :                 throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1545             :         }
    1546             : 
    1547             :         //iterator over the input BAT
    1548          18 :         inBAT_iter = bat_iterator(inBAT);
    1549          52 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1550          34 :                 str err = NULL;
    1551          34 :                 int outSingle;
    1552             : 
    1553          34 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1554          34 :                 if ((err = (*func) (&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1555           0 :                         bat_iterator_end(&inBAT_iter);
    1556           0 :                         BBPunfix(inBAT->batCacheid);
    1557           0 :                         BBPunfix(outBAT->batCacheid);
    1558           0 :                         return err;
    1559             :                 }
    1560          34 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1561           0 :                         bat_iterator_end(&inBAT_iter);
    1562           0 :                         BBPunfix(inBAT->batCacheid);
    1563           0 :                         BBPunfix(outBAT->batCacheid);
    1564           0 :                         throw(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1565             :                 }
    1566             :         }
    1567          18 :         bat_iterator_end(&inBAT_iter);
    1568             : 
    1569             :         //set the number of elements in the outBAT
    1570          18 :         BATsetcount(outBAT, BATcount(inBAT));
    1571             : 
    1572          18 :         BBPunfix(inBAT->batCacheid);
    1573          18 :         *outBAT_id = outBAT->batCacheid;
    1574          18 :         BBPkeepref(outBAT);
    1575             : 
    1576          18 :         return MAL_SUCCEED;
    1577             : 
    1578             : }
    1579             : 
    1580             : str
    1581           9 : wkbNumPoints_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1582             : {
    1583           9 :         return WKBtoINTflagINT_bat(outBAT_id, inBAT_id, flag, wkbNumPoints, "batgeom.wkbNumPoints");
    1584             : }
    1585             : 
    1586             : str
    1587           9 : wkbNumRings_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1588             : {
    1589           9 :         return WKBtoINTflagINT_bat(outBAT_id, inBAT_id, flag, wkbNumRings, "batgeom.wkbNumRings");
    1590             : }
    1591             : 
    1592             : /******************************************************************************************/
    1593             : /*************************** IN: wkb - OUT: double - FLAG: int ****************************/
    1594             : /******************************************************************************************/
    1595             : 
    1596             : str
    1597          11 : wkbGetCoordinate_bat(bat *outBAT_id, bat *inBAT_id, int *flag)
    1598             : {
    1599          11 :         BAT *outBAT = NULL, *inBAT = NULL;
    1600          11 :         wkb *inWKB = NULL;
    1601          11 :         BUN p = 0, q = 0;
    1602          11 :         BATiter inBAT_iter;
    1603             : 
    1604             :         //get the descriptor of the BAT
    1605          11 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1606           0 :                 throw(MAL, "batgeom.wkbGetCoordinate", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1607             :         }
    1608             : 
    1609             :         //create a new for the output BAT
    1610          11 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("dbl"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1611           0 :                 BBPunfix(inBAT->batCacheid);
    1612           0 :                 throw(MAL, "batgeom.wkbGetCoordinate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1613             :         }
    1614             : 
    1615             :         //iterator over the input BAT
    1616          11 :         inBAT_iter = bat_iterator(inBAT);
    1617          29 :         BATloop(inBAT, p, q) {  //iterate over all valid elements
    1618          21 :                 str err = NULL;
    1619          21 :                 double outSingle;
    1620             : 
    1621          21 :                 inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1622          21 :                 if ((err = wkbGetCoordinate(&outSingle, &inWKB, flag)) != MAL_SUCCEED) {
    1623           3 :                         bat_iterator_end(&inBAT_iter);
    1624           3 :                         BBPunfix(inBAT->batCacheid);
    1625           3 :                         BBPunfix(outBAT->batCacheid);
    1626           3 :                         return err;
    1627             :                 }
    1628          18 :                 if (BUNappend(outBAT, &outSingle, false) != GDK_SUCCEED) {
    1629           0 :                         bat_iterator_end(&inBAT_iter);
    1630           0 :                         BBPunfix(inBAT->batCacheid);
    1631           0 :                         BBPunfix(outBAT->batCacheid);
    1632           0 :                         throw(MAL, "batgeom.wkbGetCoordinate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1633             :                 }
    1634             :         }
    1635           8 :         bat_iterator_end(&inBAT_iter);
    1636             : 
    1637             :         //set the number of elements in the outBAT
    1638           8 :         BATsetcount(outBAT, BATcount(inBAT));
    1639             : 
    1640           8 :         BBPunfix(inBAT->batCacheid);
    1641           8 :         *outBAT_id = outBAT->batCacheid;
    1642           8 :         BBPkeepref(outBAT);
    1643             : 
    1644           8 :         return MAL_SUCCEED;
    1645             : 
    1646             : }
    1647             : 
    1648             : /*******************************/
    1649             : /********* Two inputs **********/
    1650             : /*******************************/
    1651             : 
    1652             : str
    1653           4 : wkbBox2D_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    1654             : {
    1655           4 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    1656           4 :         BATiter aBAT_iter, bBAT_iter;
    1657           4 :         BUN i = 0;
    1658           4 :         str ret = MAL_SUCCEED;
    1659             : 
    1660             :         //get the BATs
    1661           4 :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL || (bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    1662           0 :                 ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1663           0 :                 goto clean;
    1664             :         }
    1665             :         //check if the BATs are aligned
    1666           4 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    1667           0 :                 ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(38000) "Columns must be aligned");
    1668           0 :                 goto clean;
    1669             :         }
    1670             :         //create a new BAT for the output
    1671           4 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("mbr"), BATcount(aBAT), TRANSIENT)) == NULL) {
    1672           0 :                 ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1673           0 :                 goto clean;
    1674             :         }
    1675             : 
    1676             :         //iterator over the BATs
    1677           4 :         aBAT_iter = bat_iterator(aBAT);
    1678           4 :         bBAT_iter = bat_iterator(bBAT);
    1679             : 
    1680          24 :         for (i = 0; i < BATcount(aBAT); i++) {
    1681          16 :                 mbr *outSingle;
    1682             : 
    1683          16 :                 wkb *aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    1684          16 :                 wkb *bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    1685             : 
    1686          16 :                 if ((ret = wkbBox2D(&outSingle, &aWKB, &bWKB)) != MAL_SUCCEED) {
    1687           0 :                         BBPreclaim(outBAT);
    1688           0 :                         goto bailout;
    1689             :                 }
    1690          16 :                 if (BUNappend(outBAT, outSingle, false) != GDK_SUCCEED) {
    1691           0 :                         BBPreclaim(outBAT);
    1692           0 :                         GDKfree(outSingle);
    1693           0 :                         ret = createException(MAL, "batgeom.wkbBox2D", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1694           0 :                         goto bailout;
    1695             :                 }
    1696          16 :                 GDKfree(outSingle);
    1697             :         }
    1698             : 
    1699           4 :         *outBAT_id = outBAT->batCacheid;
    1700           4 :         BBPkeepref(outBAT);
    1701           4 :   bailout:
    1702           4 :         bat_iterator_end(&aBAT_iter);
    1703           4 :         bat_iterator_end(&bBAT_iter);
    1704             : 
    1705           4 :   clean:
    1706           4 :         BBPreclaim(aBAT);
    1707           4 :         BBPreclaim(bBAT);
    1708             : 
    1709           4 :         return ret;
    1710             : }
    1711             : 
    1712             : str
    1713           6 : wkbContains_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    1714             : {
    1715           6 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    1716           6 :         BATiter aBAT_iter, bBAT_iter;
    1717           6 :         BUN i = 0;
    1718           6 :         str ret = MAL_SUCCEED;
    1719             : 
    1720             :         //get the BATs
    1721           6 :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL || (bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    1722           0 :                 ret = createException(MAL, "batgeom.Contains", SQLSTATE(38000) "Problem retrieving BATs");
    1723           0 :                 goto clean;
    1724             :         }
    1725             :         //check if the BATs are aligned
    1726           6 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    1727           0 :                 ret = createException(MAL, "batgeom.Contains", SQLSTATE(38000) "Columns must be aligned");
    1728           0 :                 goto clean;
    1729             :         }
    1730             :         //create a new BAT for the output
    1731           6 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("bit"), BATcount(aBAT), TRANSIENT)) == NULL) {
    1732           0 :                 ret = createException(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1733           0 :                 goto clean;
    1734             :         }
    1735             : 
    1736             :         //iterator over the BATs
    1737           6 :         aBAT_iter = bat_iterator(aBAT);
    1738           6 :         bBAT_iter = bat_iterator(bBAT);
    1739             : 
    1740          17 :         for (i = 0; i < BATcount(aBAT); i++) {
    1741           5 :                 bit outBIT;
    1742             : 
    1743           5 :                 wkb *aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    1744           5 :                 wkb *bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    1745             : 
    1746           5 :                 if ((ret = wkbContains(&outBIT, &aWKB, &bWKB)) != MAL_SUCCEED) {
    1747           0 :                         BBPreclaim(outBAT);
    1748           0 :                         goto bailout;
    1749             :                 }
    1750           5 :                 if (BUNappend(outBAT, &outBIT, false) != GDK_SUCCEED) {
    1751           0 :                         BBPreclaim(outBAT);
    1752           0 :                         ret = createException(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1753           0 :                         goto bailout;
    1754             :                 }
    1755             :         }
    1756             : 
    1757           6 :         *outBAT_id = outBAT->batCacheid;
    1758           6 :         BBPkeepref(outBAT);
    1759             : 
    1760           6 :   bailout:
    1761           6 :         bat_iterator_end(&aBAT_iter);
    1762           6 :         bat_iterator_end(&bBAT_iter);
    1763             : 
    1764           6 :   clean:
    1765           6 :         BBPreclaim(aBAT);
    1766           6 :         BBPreclaim(bBAT);
    1767             : 
    1768           6 :         return ret;
    1769             : }
    1770             : 
    1771             : str
    1772           0 : wkbContains_geom_bat(bat *outBAT_id, wkb **geomWKB, bat *inBAT_id)
    1773             : {
    1774           0 :         BAT *outBAT = NULL, *inBAT = NULL;
    1775           0 :         BATiter inBAT_iter;
    1776           0 :         BUN p = 0, q = 0;
    1777             : 
    1778             :         //get the descriptor of the BAT
    1779           0 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1780           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1781             :         }
    1782             : 
    1783             :         //create a new BAT for the output
    1784           0 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("bit"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1785           0 :                 BBPunfix(inBAT->batCacheid);
    1786           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1787             :         }
    1788             : 
    1789             :         //iterator over the BATs
    1790           0 :         inBAT_iter = bat_iterator(inBAT);
    1791           0 :         BATloop(inBAT, p, q) {
    1792           0 :                 str err = NULL;
    1793           0 :                 bit outBIT;
    1794             : 
    1795           0 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1796             : 
    1797           0 :                 if ((err = wkbContains(&outBIT, geomWKB, &inWKB)) != MAL_SUCCEED) {
    1798           0 :                         bat_iterator_end(&inBAT_iter);
    1799           0 :                         BBPunfix(inBAT->batCacheid);
    1800           0 :                         BBPunfix(outBAT->batCacheid);
    1801           0 :                         return err;
    1802             :                 }
    1803           0 :                 if (BUNappend(outBAT, &outBIT, false) != GDK_SUCCEED) {
    1804           0 :                         bat_iterator_end(&inBAT_iter);
    1805           0 :                         BBPunfix(inBAT->batCacheid);
    1806           0 :                         BBPunfix(outBAT->batCacheid);
    1807           0 :                         throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1808             :                 }
    1809             :         }
    1810           0 :         bat_iterator_end(&inBAT_iter);
    1811             : 
    1812           0 :         BBPunfix(inBAT->batCacheid);
    1813           0 :         *outBAT_id = outBAT->batCacheid;
    1814           0 :         BBPkeepref(outBAT);
    1815             : 
    1816           0 :         return MAL_SUCCEED;
    1817             : 
    1818             : }
    1819             : 
    1820             : str
    1821           8 : wkbContains_bat_geom(bat *outBAT_id, bat *inBAT_id, wkb **geomWKB)
    1822             : {
    1823           8 :         BAT *outBAT = NULL, *inBAT = NULL;
    1824           8 :         BATiter inBAT_iter;
    1825           8 :         BUN p = 0, q = 0;
    1826             : 
    1827             :         //get the descriptor of the BAT
    1828           8 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1829           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1830             :         }
    1831             : 
    1832             :         //create a new BAT for the output
    1833           8 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("bit"), BATcount(inBAT), TRANSIENT)) == NULL) {
    1834           0 :                 BBPunfix(inBAT->batCacheid);
    1835           0 :                 throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1836             :         }
    1837             : 
    1838             :         //iterator over the BATs
    1839           8 :         inBAT_iter = bat_iterator(inBAT);
    1840          26 :         BATloop(inBAT, p, q) {
    1841          18 :                 str err = NULL;
    1842          18 :                 bit outBIT;
    1843             : 
    1844          18 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    1845             : 
    1846          18 :                 if ((err = wkbContains(&outBIT, &inWKB, geomWKB)) != MAL_SUCCEED) {
    1847           0 :                         bat_iterator_end(&inBAT_iter);
    1848           0 :                         BBPunfix(inBAT->batCacheid);
    1849           0 :                         BBPunfix(outBAT->batCacheid);
    1850           0 :                         return err;
    1851             :                 }
    1852          18 :                 if (BUNappend(outBAT, &outBIT, false) != GDK_SUCCEED) {
    1853           0 :                         bat_iterator_end(&inBAT_iter);
    1854           0 :                         BBPunfix(inBAT->batCacheid);
    1855           0 :                         BBPunfix(outBAT->batCacheid);
    1856           0 :                         throw(MAL, "batgeom.Contains", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1857             :                 }
    1858             :         }
    1859           8 :         bat_iterator_end(&inBAT_iter);
    1860             : 
    1861           8 :         BBPunfix(inBAT->batCacheid);
    1862           8 :         *outBAT_id = outBAT->batCacheid;
    1863           8 :         BBPkeepref(outBAT);
    1864             : 
    1865           8 :         return MAL_SUCCEED;
    1866             : }
    1867             : 
    1868             : 
    1869             : 
    1870             : /*
    1871             : str
    1872             : wkbFromWKB_bat(bat *outBAT_id, bat *inBAT_id)
    1873             : {
    1874             :         BAT *outBAT = NULL, *inBAT = NULL;
    1875             :         wkb **inWKB = NULL, *outWKB = NULL;
    1876             :         BUN i;
    1877             : 
    1878             :         //get the descriptor of the BAT
    1879             :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    1880             :                 throw(MAL, "batgeom.wkb", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1881             :         }
    1882             : 
    1883             :         //create a new BAT
    1884             :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT))) == NULL) {
    1885             :                 BBPunfix(inBAT->batCacheid);
    1886             :                 throw(MAL, "batgeom.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1887             :         }
    1888             : 
    1889             :         //pointers to the first valid elements of the x and y BATS
    1890             :         BATiter inBATi = bat_iterator(inBAT);
    1891             :         inWKB = (wkb **) inBATi.base;
    1892             :         for (i = 0; i < BATcount(inBAT); i++) {      //iterate over all valid elements
    1893             :                 str err = NULL;
    1894             :                 if ((err = wkbFromWKB(&outWKB, &inWKB[i])) != MAL_SUCCEED) {
    1895             :                         BBPunfix(inBAT->batCacheid);
    1896             :                         BBPunfix(outBAT->batCacheid);
    1897             :                         return err;
    1898             :                 }
    1899             :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    1900             :                         BBPunfix(inBAT->batCacheid);
    1901             :                         BBPunfix(outBAT->batCacheid);
    1902             :                         GDKfree(outWKB);
    1903             :                         throw(MAL, "batgeom.wkb", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1904             :                 }
    1905             :                 GDKfree(outWKB);
    1906             :                 outWKB = NULL;
    1907             :         }
    1908             :         bat_iterator_end(&inBATi);
    1909             : 
    1910             :         BBPunfix(inBAT->batCacheid);
    1911             :         *outBAT_id = outBAT->batCacheid;
    1912             :         BBPkeepref(outBAT);
    1913             :         return MAL_SUCCEED;
    1914             : 
    1915             : }
    1916             : */
    1917             : 
    1918             : /************************************/
    1919             : /********* Multiple inputs **********/
    1920             : /************************************/
    1921             : str
    1922           6 : wkbMakePoint_bat(bat *outBAT_id, bat *xBAT_id, bat *yBAT_id, bat *zBAT_id, bat *mBAT_id, int *zmFlag)
    1923             : {
    1924           6 :         BAT *outBAT = NULL, *xBAT = NULL, *yBAT = NULL, *zBAT = NULL, *mBAT = NULL;
    1925           6 :         BATiter xBAT_iter, yBAT_iter, zBAT_iter, mBAT_iter;
    1926           6 :         BUN i;
    1927           6 :         str ret = MAL_SUCCEED;
    1928             : 
    1929           6 :         if (*zmFlag == 11)
    1930           1 :                 throw(MAL, "batgeom.wkbMakePoint", SQLSTATE(38000) "POINTZM is not supported");
    1931             : 
    1932             :         //get the BATs
    1933           5 :         if ((xBAT = BATdescriptor(*xBAT_id)) == NULL || (yBAT = BATdescriptor(*yBAT_id)) == NULL || (*zmFlag == 10 && (zBAT = BATdescriptor(*zBAT_id)) == NULL)
    1934           5 :             || (*zmFlag == 1 && (mBAT = BATdescriptor(*mBAT_id)) == NULL)) {
    1935             : 
    1936           0 :                 ret = createException(MAL, "batgeom.wkbMakePoint", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1937           0 :                 goto clean;
    1938             :         }
    1939             :         //check if the BATs are aligned
    1940           5 :         if (xBAT->hseqbase != yBAT->hseqbase ||
    1941           5 :             BATcount(xBAT) != BATcount(yBAT) ||
    1942           5 :             (zBAT && (xBAT->hseqbase != zBAT->hseqbase || BATcount(xBAT) != BATcount(zBAT))) ||
    1943           1 :             (mBAT && (xBAT->hseqbase != mBAT->hseqbase || BATcount(xBAT) != BATcount(mBAT)))) {
    1944           0 :                 ret = createException(MAL, "batgeom.wkbMakePoint", SQLSTATE(38000) "Columns must be aligned");
    1945           0 :                 goto clean;
    1946             :         }
    1947             :         //create a new BAT for the output
    1948           5 :         if ((outBAT = COLnew(xBAT->hseqbase, ATOMindex("wkb"), BATcount(xBAT), TRANSIENT)) == NULL) {
    1949           0 :                 ret = createException(MAL, "batgeom.wkbMakePoint", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1950           0 :                 goto clean;
    1951             :         }
    1952             : 
    1953             :         //iterator over the BATs
    1954           5 :         xBAT_iter = bat_iterator(xBAT);
    1955           5 :         yBAT_iter = bat_iterator(yBAT);
    1956           5 :         if (zBAT)
    1957           1 :                 zBAT_iter = bat_iterator(zBAT);
    1958           5 :         if (mBAT)
    1959           1 :                 mBAT_iter = bat_iterator(mBAT);
    1960             : 
    1961          18 :         for (i = 0; i < BATcount(xBAT); i++) {
    1962          13 :                 wkb *pointWKB = NULL;
    1963             : 
    1964          13 :                 double x = *((double *) BUNtloc(xBAT_iter, i));
    1965          13 :                 double y = *((double *) BUNtloc(yBAT_iter, i));
    1966          13 :                 double z = 0.0;
    1967          13 :                 double m = 0.0;
    1968             : 
    1969          13 :                 if (zBAT)
    1970           3 :                         z = *((double *) BUNtloc(zBAT_iter, i));
    1971          13 :                 if (mBAT)
    1972           3 :                         m = *((double *) BUNtloc(mBAT_iter, i));
    1973             : 
    1974          13 :                 if ((ret = wkbMakePoint(&pointWKB, &x, &y, &z, &m, zmFlag)) != MAL_SUCCEED) {       //check
    1975             : 
    1976           0 :                         BBPreclaim(outBAT);
    1977           0 :                         goto bailout;
    1978             :                 }
    1979          13 :                 if (BUNappend(outBAT, pointWKB, false) != GDK_SUCCEED) {
    1980           0 :                         BBPreclaim(outBAT);
    1981           0 :                         GDKfree(pointWKB);
    1982           0 :                         ret = createException(MAL, "batgeom.WkbMakePoint", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1983           0 :                         goto bailout;
    1984             :                 }
    1985          13 :                 GDKfree(pointWKB);
    1986             :         }
    1987             : 
    1988           5 :         *outBAT_id = outBAT->batCacheid;
    1989           5 :         BBPkeepref(outBAT);
    1990             : 
    1991           5 :   bailout:
    1992           5 :         bat_iterator_end(&xBAT_iter);
    1993           5 :         bat_iterator_end(&yBAT_iter);
    1994           5 :         if (zBAT)
    1995           1 :                 bat_iterator_end(&zBAT_iter);
    1996           5 :         if (mBAT)
    1997           1 :                 bat_iterator_end(&mBAT_iter);
    1998           4 :   clean:
    1999           5 :         BBPreclaim(xBAT);
    2000           5 :         BBPreclaim(yBAT);
    2001           5 :         BBPreclaim(zBAT);
    2002           5 :         BBPreclaim(mBAT);
    2003             : 
    2004             :         return ret;
    2005             : }
    2006             : 
    2007             : 
    2008             : /* sets the srid of the geometry - BULK version*/
    2009             : str
    2010           0 : wkbSetSRID_bat(bat *outBAT_id, bat *inBAT_id, int *srid)
    2011             : {
    2012           0 :         BAT *outBAT = NULL, *inBAT = NULL;
    2013           0 :         BUN p = 0, q = 0;
    2014           0 :         BATiter inBAT_iter;
    2015             : 
    2016             :         //get the descriptor of the BAT
    2017           0 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    2018           0 :                 throw(MAL, "batgeom.SetSRID", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2019             :         }
    2020             : 
    2021             :         //create a new BAT for the output
    2022           0 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("wkb"), BATcount(inBAT), TRANSIENT)) == NULL) {
    2023           0 :                 BBPunfix(inBAT->batCacheid);
    2024           0 :                 throw(MAL, "batgeom.SetSRID", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2025             :         }
    2026             : 
    2027             :         //iterator over the BATs
    2028           0 :         inBAT_iter = bat_iterator(inBAT);
    2029           0 :         BATloop(inBAT, p, q) {
    2030           0 :                 str err = NULL;
    2031           0 :                 wkb *outWKB = NULL;
    2032             : 
    2033           0 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    2034             : 
    2035           0 :                 if ((err = wkbSetSRID(&outWKB, &inWKB, srid)) != MAL_SUCCEED) { //set SRID
    2036           0 :                         bat_iterator_end(&inBAT_iter);
    2037           0 :                         BBPunfix(inBAT->batCacheid);
    2038           0 :                         BBPunfix(outBAT->batCacheid);
    2039           0 :                         return err;
    2040             :                 }
    2041           0 :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    2042           0 :                         bat_iterator_end(&inBAT_iter);
    2043           0 :                         BBPunfix(inBAT->batCacheid);
    2044           0 :                         BBPunfix(outBAT->batCacheid);
    2045           0 :                         GDKfree(outWKB);
    2046           0 :                         throw(MAL, "batgeom.SetSRID", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2047             :                 }
    2048           0 :                 GDKfree(outWKB);
    2049           0 :                 outWKB = NULL;
    2050             :         }
    2051           0 :         bat_iterator_end(&inBAT_iter);
    2052             : 
    2053           0 :         BBPunfix(inBAT->batCacheid);
    2054           0 :         *outBAT_id = outBAT->batCacheid;
    2055           0 :         BBPkeepref(outBAT);
    2056             : 
    2057           0 :         return MAL_SUCCEED;
    2058             : }
    2059             : 
    2060             : str
    2061           5 : wkbDistance_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    2062             : {
    2063           5 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    2064           5 :         BATiter aBAT_iter, bBAT_iter;
    2065           5 :         BUN i = 0;
    2066           5 :         str ret = MAL_SUCCEED;
    2067             : 
    2068             :         //get the BATs
    2069           5 :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL || (bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    2070           0 :                 ret = createException(MAL, "batgeom.Distance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2071           0 :                 goto clean;
    2072             :         }
    2073             :         //check if the BATs are aligned
    2074           5 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    2075           0 :                 ret = createException(MAL, "batgeom.Distance", SQLSTATE(38000) "Columns must be aligned");
    2076           0 :                 goto clean;
    2077             :         }
    2078             :         //create a new BAT for the output
    2079           5 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("dbl"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2080           0 :                 ret = createException(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2081           0 :                 goto clean;
    2082             :         }
    2083             : 
    2084             :         //iterator over the BATs
    2085           5 :         aBAT_iter = bat_iterator(aBAT);
    2086           5 :         bBAT_iter = bat_iterator(bBAT);
    2087             : 
    2088          14 :         for (i = 0; i < BATcount(aBAT); i++) {
    2089           4 :                 double distanceVal = 0;
    2090             : 
    2091           4 :                 wkb *aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2092           4 :                 wkb *bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2093             : 
    2094           4 :                 if ((ret = wkbDistance(&distanceVal, &aWKB, &bWKB)) != MAL_SUCCEED) {       //check
    2095             : 
    2096           0 :                         BBPreclaim(outBAT);
    2097           0 :                         goto bailout;
    2098             :                 }
    2099           4 :                 if (BUNappend(outBAT, &distanceVal, false) != GDK_SUCCEED) {
    2100           0 :                         BBPreclaim(outBAT);
    2101           0 :                         ret = createException(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2102           0 :                         goto bailout;
    2103             :                 }
    2104             :         }
    2105             : 
    2106           5 :         *outBAT_id = outBAT->batCacheid;
    2107           5 :         BBPkeepref(outBAT);
    2108             : 
    2109           5 :   bailout:
    2110           5 :         bat_iterator_end(&aBAT_iter);
    2111           5 :         bat_iterator_end(&bBAT_iter);
    2112           5 :   clean:
    2113           5 :         BBPreclaim(aBAT);
    2114           5 :         BBPreclaim(bBAT);
    2115             : 
    2116           5 :         return ret;
    2117             : 
    2118             : }
    2119             : 
    2120             : str
    2121           0 : wkbDistance_geom_bat(bat *outBAT_id, wkb **geomWKB, bat *inBAT_id)
    2122             : {
    2123           0 :         BAT *outBAT = NULL, *inBAT = NULL;
    2124           0 :         BATiter inBAT_iter;
    2125           0 :         BUN p = 0, q = 0;
    2126             : 
    2127             :         //get the descriptor of the BAT
    2128           0 :         if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) {
    2129           0 :                 throw(MAL, "batgeom.Distance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2130             :         }
    2131             : 
    2132             :         //create a new BAT for the output
    2133           0 :         if ((outBAT = COLnew(inBAT->hseqbase, ATOMindex("dbl"), BATcount(inBAT), TRANSIENT)) == NULL) {
    2134           0 :                 BBPunfix(inBAT->batCacheid);
    2135           0 :                 throw(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2136             :         }
    2137             : 
    2138             :         //iterator over the BAT
    2139           0 :         inBAT_iter = bat_iterator(inBAT);
    2140           0 :         BATloop(inBAT, p, q) {
    2141           0 :                 str err = NULL;
    2142           0 :                 double distanceVal = 0;
    2143             : 
    2144           0 :                 wkb *inWKB = (wkb *) BUNtvar(inBAT_iter, p);
    2145             : 
    2146           0 :                 if ((err = wkbDistance(&distanceVal, geomWKB, &inWKB)) != MAL_SUCCEED) {        //check
    2147           0 :                         bat_iterator_end(&inBAT_iter);
    2148           0 :                         BBPunfix(inBAT->batCacheid);
    2149           0 :                         BBPunfix(outBAT->batCacheid);
    2150           0 :                         return err;
    2151             :                 }
    2152           0 :                 if (BUNappend(outBAT, &distanceVal, false) != GDK_SUCCEED) {
    2153           0 :                         bat_iterator_end(&inBAT_iter);
    2154           0 :                         BBPunfix(inBAT->batCacheid);
    2155           0 :                         BBPunfix(outBAT->batCacheid);
    2156           0 :                         throw(MAL, "batgeom.Distance", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2157             :                 }
    2158             :         }
    2159           0 :         bat_iterator_end(&inBAT_iter);
    2160             : 
    2161           0 :         BBPunfix(inBAT->batCacheid);
    2162           0 :         *outBAT_id = outBAT->batCacheid;
    2163           0 :         BBPkeepref(outBAT);
    2164             : 
    2165           0 :         return MAL_SUCCEED;
    2166             : }
    2167             : 
    2168             : str
    2169           0 : wkbDistance_bat_geom(bat *outBAT_id, bat *inBAT_id, wkb **geomWKB)
    2170             : {
    2171           0 :         return wkbDistance_geom_bat(outBAT_id, geomWKB, inBAT_id);
    2172             : }
    2173             : 
    2174             : /**
    2175             :  * It filters the geometry in the second BAT with respect to the MBR of the geometry in the first BAT.
    2176             :  **/
    2177             : /*
    2178             : str
    2179             : wkbFilter_bat(bat *aBATfiltered_id, bat *bBATfiltered_id, bat *aBAT_id, bat *bBAT_id)
    2180             : {
    2181             :         BAT *aBATfiltered = NULL, *bBATfiltered = NULL, *aBAT = NULL, *bBAT = NULL;
    2182             :         wkb *aWKB = NULL, *bWKB = NULL;
    2183             :         bit outBIT;
    2184             :         BATiter aBAT_iter, bBAT_iter;
    2185             :         BUN i = 0;
    2186             : 
    2187             :         //get the descriptor of the BAT
    2188             :         if ((aBAT = BATdescriptor(*aBAT_id)) == NULL) {
    2189             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2190             :         }
    2191             :         if ((bBAT = BATdescriptor(*bBAT_id)) == NULL) {
    2192             :                 BBPunfix(aBAT->batCacheid);
    2193             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2194             :         }
    2195             : 
    2196             :         if (aBAT->hseqbase != bBAT->hseqbase ||   //the idxs of the headers of the BATs are not the same
    2197             :             BATcount(aBAT) != BATcount(bBAT)) { //the number of valid elements in the BATs are not the same
    2198             :                 BBPunfix(aBAT->batCacheid);
    2199             :                 BBPunfix(bBAT->batCacheid);
    2200             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(38000) "The arguments must have dense and aligned heads");
    2201             :         }
    2202             :         //create two new BATs for the output
    2203             :         if ((aBATfiltered = COLnew(aBAT->hseqbase, ATOMindex("wkb"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2204             :                 BBPunfix(aBAT->batCacheid);
    2205             :                 BBPunfix(bBAT->batCacheid);
    2206             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2207             :         }
    2208             :         if ((bBATfiltered = COLnew(bBAT->hseqbase, ATOMindex("wkb"), BATcount(bBAT), TRANSIENT)) == NULL) {
    2209             :                 BBPunfix(aBAT->batCacheid);
    2210             :                 BBPunfix(bBAT->batCacheid);
    2211             :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2212             :         }
    2213             : 
    2214             :         //iterator over the BATs
    2215             :         aBAT_iter = bat_iterator(aBAT);
    2216             :         bBAT_iter = bat_iterator(bBAT);
    2217             : 
    2218             :         for (i = 0; i < BATcount(aBAT); i++) {
    2219             :                 str err = NULL;
    2220             :                 aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2221             :                 bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2222             : 
    2223             :                 //check the containment of the MBRs
    2224             :                 if ((err = mbrOverlaps_wkb(&outBIT, &aWKB, &bWKB)) != MAL_SUCCEED) {
    2225             :                         bat_iterator_end(&aBAT_iter);
    2226             :                         bat_iterator_end(&bBAT_iter);
    2227             :                         BBPunfix(aBAT->batCacheid);
    2228             :                         BBPunfix(bBAT->batCacheid);
    2229             :                         BBPunfix(aBATfiltered->batCacheid);
    2230             :                         BBPunfix(bBATfiltered->batCacheid);
    2231             :                         return err;
    2232             :                 }
    2233             :                 if (outBIT) {
    2234             :                         if (BUNappend(aBATfiltered, aWKB, false) != GDK_SUCCEED ||
    2235             :                             BUNappend(bBATfiltered, bWKB, false) != GDK_SUCCEED) {
    2236             :                                 bat_iterator_end(&aBAT_iter);
    2237             :                                 bat_iterator_end(&bBAT_iter);
    2238             :                                 BBPunfix(aBAT->batCacheid);
    2239             :                                 BBPunfix(bBAT->batCacheid);
    2240             :                                 BBPunfix(aBATfiltered->batCacheid);
    2241             :                                 BBPunfix(bBATfiltered->batCacheid);
    2242             :                                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2243             :                         }
    2244             :                 }
    2245             :         }
    2246             :         bat_iterator_end(&aBAT_iter);
    2247             :         bat_iterator_end(&bBAT_iter);
    2248             : 
    2249             :         BBPunfix(aBAT->batCacheid);
    2250             :         BBPunfix(bBAT->batCacheid);
    2251             :         *aBATfiltered_id = aBATfiltered->batCacheid;
    2252             :         BBPkeepref(aBATfiltered);
    2253             :         *bBATfiltered_id = bBATfiltered->batCacheid;
    2254             :         BBPkeepref(bBATfiltered);
    2255             : 
    2256             :         return MAL_SUCCEED;
    2257             : 
    2258             : 
    2259             : }
    2260             : */
    2261             : 
    2262             : /**
    2263             :  * It filters the geometry in the second BAT with respect to the MBR of the geometry in the first BAT.
    2264             :  **/
    2265             : str
    2266           0 : wkbFilter_geom_bat(bat *BATfiltered_id, wkb **geomWKB, bat *BAToriginal_id)
    2267             : {
    2268           0 :         BAT *BATfiltered = NULL, *BAToriginal = NULL;
    2269           0 :         wkb *WKBoriginal = NULL;
    2270           0 :         BATiter BAToriginal_iter;
    2271           0 :         BUN i = 0;
    2272           0 :         mbr *geomMBR;
    2273           0 :         str err = NULL;
    2274             : 
    2275             :         //get the descriptor of the BAT
    2276           0 :         if ((BAToriginal = BATdescriptor(*BAToriginal_id)) == NULL) {
    2277           0 :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2278             :         }
    2279             : 
    2280             :         //create the new BAT
    2281           0 :         if ((BATfiltered = COLnew(BAToriginal->hseqbase, ATOMindex("wkb"), BATcount(BAToriginal), TRANSIENT)) == NULL) {
    2282           0 :                 BBPunfix(BAToriginal->batCacheid);
    2283           0 :                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2284             :         }
    2285             : 
    2286             :         //create the MBR of the geom
    2287           0 :         if ((err = wkbMBR(&geomMBR, geomWKB)) != MAL_SUCCEED) {
    2288           0 :                 BBPunfix(BAToriginal->batCacheid);
    2289           0 :                 BBPunfix(BATfiltered->batCacheid);
    2290           0 :                 return err;
    2291             :         }
    2292             : 
    2293             :         //iterator over the BAT
    2294           0 :         BAToriginal_iter = bat_iterator(BAToriginal);
    2295             : 
    2296           0 :         for (i = 0; i < BATcount(BAToriginal); i++) {
    2297           0 :                 str err = NULL;
    2298           0 :                 mbr *MBRoriginal;
    2299           0 :                 bit outBIT = 0;
    2300             : 
    2301           0 :                 WKBoriginal = (wkb *) BUNtvar(BAToriginal_iter, i);
    2302             : 
    2303             :                 //create the MBR for each geometry in the BAT
    2304           0 :                 if ((err = wkbMBR(&MBRoriginal, &WKBoriginal)) != MAL_SUCCEED) {
    2305           0 :                         bat_iterator_end(&BAToriginal_iter);
    2306           0 :                         BBPunfix(BAToriginal->batCacheid);
    2307           0 :                         BBPunfix(BATfiltered->batCacheid);
    2308           0 :                         GDKfree(geomMBR);
    2309           0 :                         return err;
    2310             :                 }
    2311             :                 //check the containment of the MBRs
    2312           0 :                 if ((err = mbrOverlaps(&outBIT, &geomMBR, &MBRoriginal)) != MAL_SUCCEED) {
    2313           0 :                         bat_iterator_end(&BAToriginal_iter);
    2314           0 :                         BBPunfix(BAToriginal->batCacheid);
    2315           0 :                         BBPunfix(BATfiltered->batCacheid);
    2316           0 :                         GDKfree(geomMBR);
    2317           0 :                         GDKfree(MBRoriginal);
    2318           0 :                         return err;
    2319             :                 }
    2320             : 
    2321           0 :                 if (outBIT) {
    2322           0 :                         if (BUNappend(BATfiltered, WKBoriginal, false) != GDK_SUCCEED) {
    2323           0 :                                 bat_iterator_end(&BAToriginal_iter);
    2324           0 :                                 BBPunfix(BAToriginal->batCacheid);
    2325           0 :                                 BBPunfix(BATfiltered->batCacheid);
    2326           0 :                                 GDKfree(geomMBR);
    2327           0 :                                 GDKfree(MBRoriginal);
    2328           0 :                                 throw(MAL, "batgeom.MBRfilter", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2329             :                         }
    2330             :                 }
    2331             : 
    2332           0 :                 GDKfree(MBRoriginal);
    2333             :         }
    2334           0 :         bat_iterator_end(&BAToriginal_iter);
    2335             : 
    2336           0 :         GDKfree(geomMBR);
    2337           0 :         BBPunfix(BAToriginal->batCacheid);
    2338           0 :         *BATfiltered_id = BATfiltered->batCacheid;
    2339           0 :         BBPkeepref(BATfiltered);
    2340             : 
    2341           0 :         return MAL_SUCCEED;
    2342             : 
    2343             : }
    2344             : 
    2345             : str
    2346           0 : wkbFilter_bat_geom(bat *BATfiltered_id, bat *BAToriginal_id, wkb **geomWKB)
    2347             : {
    2348           0 :         return wkbFilter_geom_bat(BATfiltered_id, geomWKB, BAToriginal_id);
    2349             : }
    2350             : 
    2351             : /* MBR */
    2352             : str
    2353           4 : wkbCoordinateFromWKB_bat(bat *outBAT_id, bat *inBAT_id, int *coordinateIdx)
    2354             : {
    2355           4 :         str err = NULL;
    2356           4 :         bat inBAT_mbr_id = 0;   //the id of the bat with the mbrs
    2357             : 
    2358           4 :         if ((err = wkbMBR_bat(&inBAT_mbr_id, inBAT_id)) != MAL_SUCCEED) {
    2359             :                 return err;
    2360             :         }
    2361             :         //call the bulk version of wkbCoordinateFromMBR
    2362           4 :         err = wkbCoordinateFromMBR_bat(outBAT_id, &inBAT_mbr_id, coordinateIdx);
    2363           4 :         BBPrelease(inBAT_mbr_id);
    2364           4 :         return err;
    2365             : }
    2366             : 
    2367             : str
    2368           1 : wkbMakeLine_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    2369             : {
    2370           1 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    2371           1 :         BATiter aBAT_iter, bBAT_iter;
    2372           1 :         BUN i;
    2373             : 
    2374             :         //get the BATs
    2375           1 :         aBAT = BATdescriptor(*aBAT_id);
    2376           1 :         bBAT = BATdescriptor(*bBAT_id);
    2377           1 :         if (aBAT == NULL || bBAT == NULL) {
    2378           0 :                 BBPreclaim(aBAT);
    2379           0 :                 BBPreclaim(bBAT);
    2380           0 :                 throw(MAL, "batgeom.MakeLine", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2381             :         }
    2382             :         //check if the BATs are aligned
    2383           1 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    2384           0 :                 BBPunfix(aBAT->batCacheid);
    2385           0 :                 BBPunfix(bBAT->batCacheid);
    2386           0 :                 throw(MAL, "batgeom.MakeLine", SQLSTATE(38000) "Columns must be aligned");
    2387             :         }
    2388             :         //create a new BAT for the output
    2389           1 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("wkb"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2390           0 :                 BBPunfix(aBAT->batCacheid);
    2391           0 :                 BBPunfix(bBAT->batCacheid);
    2392           0 :                 throw(MAL, "batgeom.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2393             :         }
    2394             : 
    2395             :         //iterator over the BATs
    2396           1 :         aBAT_iter = bat_iterator(aBAT);
    2397           1 :         bBAT_iter = bat_iterator(bBAT);
    2398             : 
    2399           4 :         for (i = 0; i < BATcount(aBAT); i++) {
    2400           2 :                 str err = NULL;
    2401           2 :                 wkb *aWKB = NULL, *bWKB = NULL, *outWKB = NULL;
    2402             : 
    2403           2 :                 aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2404           2 :                 bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2405             : 
    2406           2 :                 if ((err = wkbMakeLine(&outWKB, &aWKB, &bWKB)) != MAL_SUCCEED) {    //check
    2407           0 :                         bat_iterator_end(&aBAT_iter);
    2408           0 :                         bat_iterator_end(&bBAT_iter);
    2409           0 :                         BBPunfix(outBAT->batCacheid);
    2410           0 :                         BBPunfix(aBAT->batCacheid);
    2411           0 :                         BBPunfix(bBAT->batCacheid);
    2412           0 :                         return err;
    2413             :                 }
    2414           2 :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    2415           0 :                         bat_iterator_end(&aBAT_iter);
    2416           0 :                         bat_iterator_end(&bBAT_iter);
    2417           0 :                         BBPunfix(outBAT->batCacheid);
    2418           0 :                         BBPunfix(aBAT->batCacheid);
    2419           0 :                         BBPunfix(bBAT->batCacheid);
    2420           0 :                         GDKfree(outWKB);
    2421           0 :                         throw(MAL, "batgeom.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2422             :                 }
    2423           2 :                 GDKfree(outWKB);
    2424           2 :                 outWKB = NULL;
    2425             :         }
    2426           1 :         bat_iterator_end(&aBAT_iter);
    2427           1 :         bat_iterator_end(&bBAT_iter);
    2428             : 
    2429           1 :         *outBAT_id = outBAT->batCacheid;
    2430           1 :         BBPkeepref(outBAT);
    2431           1 :         BBPunfix(aBAT->batCacheid);
    2432           1 :         BBPunfix(bBAT->batCacheid);
    2433             : 
    2434           1 :         return MAL_SUCCEED;
    2435             : }
    2436             : 
    2437             : str
    2438           2 : wkbUnion_bat(bat *outBAT_id, bat *aBAT_id, bat *bBAT_id)
    2439             : {
    2440           2 :         BAT *outBAT = NULL, *aBAT = NULL, *bBAT = NULL;
    2441           2 :         BATiter aBAT_iter, bBAT_iter;
    2442           2 :         BUN i;
    2443             : 
    2444             :         //get the BATs
    2445           2 :         aBAT = BATdescriptor(*aBAT_id);
    2446           2 :         bBAT = BATdescriptor(*bBAT_id);
    2447           2 :         if (aBAT == NULL || bBAT == NULL) {
    2448           0 :                 BBPreclaim(aBAT);
    2449           0 :                 BBPreclaim(bBAT);
    2450           0 :                 throw(MAL, "batgeom.Union", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2451             :         }
    2452             :         //check if the BATs are aligned
    2453           2 :         if (aBAT->hseqbase != bBAT->hseqbase || BATcount(aBAT) != BATcount(bBAT)) {
    2454           0 :                 BBPunfix(aBAT->batCacheid);
    2455           0 :                 BBPunfix(bBAT->batCacheid);
    2456           0 :                 throw(MAL, "batgeom.Union", SQLSTATE(38000) "Columns must be aligned");
    2457             :         }
    2458             :         //create a new BAT for the output
    2459           2 :         if ((outBAT = COLnew(aBAT->hseqbase, ATOMindex("wkb"), BATcount(aBAT), TRANSIENT)) == NULL) {
    2460           0 :                 BBPunfix(aBAT->batCacheid);
    2461           0 :                 BBPunfix(bBAT->batCacheid);
    2462           0 :                 throw(MAL, "batgeom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2463             :         }
    2464             : 
    2465             :         //iterator over the BATs
    2466           2 :         aBAT_iter = bat_iterator(aBAT);
    2467           2 :         bBAT_iter = bat_iterator(bBAT);
    2468             : 
    2469           5 :         for (i = 0; i < BATcount(aBAT); i++) {
    2470           1 :                 str err = NULL;
    2471           1 :                 wkb *aWKB = NULL, *bWKB = NULL, *outWKB = NULL;
    2472             : 
    2473           1 :                 aWKB = (wkb *) BUNtvar(aBAT_iter, i);
    2474           1 :                 bWKB = (wkb *) BUNtvar(bBAT_iter, i);
    2475             : 
    2476           1 :                 if ((err = wkbUnion(&outWKB, &aWKB, &bWKB)) != MAL_SUCCEED) {       //check
    2477           0 :                         bat_iterator_end(&aBAT_iter);
    2478           0 :                         bat_iterator_end(&bBAT_iter);
    2479           0 :                         BBPunfix(outBAT->batCacheid);
    2480           0 :                         BBPunfix(aBAT->batCacheid);
    2481           0 :                         BBPunfix(bBAT->batCacheid);
    2482           0 :                         return err;
    2483             :                 }
    2484           1 :                 if (BUNappend(outBAT, outWKB, false) != GDK_SUCCEED) {
    2485           0 :                         bat_iterator_end(&aBAT_iter);
    2486           0 :                         bat_iterator_end(&bBAT_iter);
    2487           0 :                         BBPunfix(outBAT->batCacheid);
    2488           0 :                         BBPunfix(aBAT->batCacheid);
    2489           0 :                         BBPunfix(bBAT->batCacheid);
    2490           0 :                         GDKfree(outWKB);
    2491           0 :                         throw(MAL, "batgeom.Union", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2492             :                 }
    2493           1 :                 GDKfree(outWKB);
    2494           1 :                 outWKB = NULL;
    2495             :         }
    2496           2 :         bat_iterator_end(&aBAT_iter);
    2497           2 :         bat_iterator_end(&bBAT_iter);
    2498             : 
    2499           2 :         *outBAT_id = outBAT->batCacheid;
    2500           2 :         BBPkeepref(outBAT);
    2501           2 :         BBPunfix(aBAT->batCacheid);
    2502           2 :         BBPunfix(bBAT->batCacheid);
    2503             : 
    2504           2 :         return MAL_SUCCEED;
    2505             : }

Generated by: LCOV version 1.14