-#if POSTGIS_PGSQL_VERSION >= 80
#include "commands/vacuum.h"
#include "utils/lsyscache.h"
static float8 estimate_selectivity(BOX2DFLOAT4 *box, GEOM_STATS *geomstats);
-#endif /* POSTGIS_PGSQL_VERSION >= 80 */
#define SHOW_DIGS_DOUBLE 15
#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
*/
#define REALLY_DO_JOINSEL 1
-/* --------------------------------------------
- * lwhistogram2d type
- *
- * 2d histogram is a bounding box with a bunch of cells in it.
- * The cells will have width (xmax-xmin)/boxesPerSide
- * and height(ymax-ymin)/boxesPerSide
- * The first box is the ll corner's box, the send is directly to the right
- * (row-major).
- *
- * Size of structure is:
- * 4 (size) + 32 (box) + 4 (boxesPerSide) +
- * boxesPerSide*boxesPerSide*4 (data)
- */
-typedef struct histotag
-{
- int32 size; /* postgres variable-length type requirement */
- int boxesPerSide; /* boxesPerSide * boxesPerSide = total boxes in grid */
- double avgFeatureArea; /* average bbox area of features in this histogram */
- double xmin,ymin, xmax, ymax; /* BOX of area */
- unsigned int value[1]; /* variable length # of ints for histogram */
-} LWHISTOGRAM2D;
-
-Datum lwhistogram2d_in(PG_FUNCTION_ARGS);
-Datum lwhistogram2d_out(PG_FUNCTION_ARGS);
-Datum create_lwhistogram2d(PG_FUNCTION_ARGS);
-Datum build_lwhistogram2d(PG_FUNCTION_ARGS);
-Datum explode_lwhistogram2d(PG_FUNCTION_ARGS);
-Datum estimate_lwhistogram2d(PG_FUNCTION_ARGS);
Datum LWGEOM_gist_sel(PG_FUNCTION_ARGS);
Datum LWGEOM_gist_joinsel(PG_FUNCTION_ARGS);
Datum LWGEOM_estimated_extent(PG_FUNCTION_ARGS);
-#if POSTGIS_PGSQL_VERSION >= 80
Datum LWGEOM_analyze(PG_FUNCTION_ARGS);
-#endif
-
-/*
- * text form of LWHISTOGRAM2D is:
- * 'HISTOGRAM2D(xmin,ymin,xmax,ymax,boxesPerSide;value[0],value[1],...')
- * note the ";" in the middle (for easy parsing)
- * I dont expect anyone to actually create one by hand
- */
-PG_FUNCTION_INFO_V1(lwhistogram2d_in);
-Datum lwhistogram2d_in(PG_FUNCTION_ARGS)
-{
- char *str = PG_GETARG_CSTRING(0);
- LWHISTOGRAM2D *histo ;
- int nitems;
- double xmin,ymin,xmax,ymax;
- int boxesPerSide;
- double avgFeatureArea;
- char *str2,*str3;
- long datum;
-
- /*elog(NOTICE, "lwhistogram2d parser called");*/
-
- int t;
-
- while (isspace(*str))
- str++;
-
- if (strstr(str,"HISTOGRAM2D(") != str)
- {
- elog(ERROR, "lwhistogram2d parser - doesnt start with 'HISTOGRAM2D(\n");
- PG_RETURN_NULL() ;
- }
- if (strstr(str,";") == NULL)
- {
- elog(ERROR, "lwhistogram2d parser - doesnt have a ; in sring!\n");
- PG_RETURN_NULL() ;
- }
-
- nitems = sscanf(str,"HISTOGRAM2D(%lf,%lf,%lf,%lf,%i,%lf;",&xmin,&ymin,&xmax,&ymax,&boxesPerSide,&avgFeatureArea);
-
- if (nitems != 6)
- {
- elog(ERROR, "lwhistogram2d parser - couldnt parse initial portion of histogram!\n");
- PG_RETURN_NULL() ;
- }
-
- if ( (boxesPerSide > 50) || (boxesPerSide <1) )
- {
- elog(ERROR, "lwhistogram2d parser - boxesPerSide is too big or too small\n");
- PG_RETURN_NULL() ;
- }
-
- str2 = strstr(str,";");
- str2++;
-
- if (str2[0] ==0)
- {
- elog(ERROR, "lwhistogram2d parser - no histogram values\n");
- PG_RETURN_NULL() ;
- }
-
- histo = (LWHISTOGRAM2D *) palloc (sizeof(LWHISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 );
- histo->size = sizeof(LWHISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4;
-
- for (t=0;t<boxesPerSide*boxesPerSide;t++)
- {
- datum = strtol(str2,&str3,10); /* str2=start of int, str3=end of int, base 10 */
- /* str3 points to "," or ")" */
- if (str3[0] ==0)
- {
- elog(ERROR, "lwhistogram2d parser - histogram values prematurely ended!\n");
- PG_RETURN_NULL() ;
- }
- histo->value[t] = (unsigned int) datum;
- str2= str3+1; /* move past the "," or ")" */
- }
- histo->xmin = xmin;
- histo->xmax = xmax;
- histo->ymin = ymin;
- histo->ymax = ymax;
- histo->avgFeatureArea = avgFeatureArea;
- histo->boxesPerSide = boxesPerSide;
-
- PG_RETURN_POINTER(histo);
-}
-
-
-
-/* text version */
-PG_FUNCTION_INFO_V1(lwhistogram2d_out);
-Datum lwhistogram2d_out(PG_FUNCTION_ARGS)
-{
- LWHISTOGRAM2D *histo = (LWHISTOGRAM2D *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- char *result;
- int t;
- char temp[100];
- int size;
-
- size = 26+6*MAX_DIGS_DOUBLE + histo->boxesPerSide*histo->boxesPerSide* (MAX_DIGS_DOUBLE+1);
- result = palloc(size);
-
- sprintf(result,"HISTOGRAM2D(%.15g,%.15g,%.15g,%.15g,%i,%.15g;",
- histo->xmin,histo->ymin,histo->xmax,histo->ymax,histo->boxesPerSide,histo->avgFeatureArea );
-
- POSTGIS_DEBUGF(3, "so far: %s",result);
- POSTGIS_DEBUGF(3, "buffsize=%i, size=%i",size,histo->size);
-
- for (t=0;t<histo->boxesPerSide*histo->boxesPerSide;t++)
- {
- if (t) sprintf(temp, ",%u", histo->value[t]);
- else sprintf(temp, "%u", histo->value[t]);
- strcat(result,temp);
- }
-
- strcat(result,")");
-
- POSTGIS_DEBUGF(3, "about to return string (len=%d): -%s-", (int)strlen(result),result);
- POSTGIS_DEBUGF(3, "result@%p", result);
-
- PG_RETURN_CSTRING(result);
-}
-
-/*create_lwhistogram2d(BOX2D, boxesPerSide)*/
-/* returns a histgram with 0s in all the boxes.*/
-PG_FUNCTION_INFO_V1(create_lwhistogram2d);
-Datum create_lwhistogram2d(PG_FUNCTION_ARGS)
-{
- /*BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0);*/
- BOX2DFLOAT4 *bbox = (BOX2DFLOAT4 *)PG_GETARG_DATUM(0);
- int32 boxesPerSide = PG_GETARG_INT32(1);
- LWHISTOGRAM2D *histo;
- int size,t;
-
- if ( (boxesPerSide <1) || (boxesPerSide >50) )
- {
- elog(ERROR, "create_lwhistogram2d - boxesPerSide is too small or big.\n");
- PG_RETURN_NULL() ;
- }
-
- size = sizeof(LWHISTOGRAM2D) + (boxesPerSide*boxesPerSide-1)*4 ;
-
- histo = (LWHISTOGRAM2D *)palloc(size);
- histo->size = size;
- histo->xmin = bbox->xmin;
- histo->ymin = bbox->ymin;
- histo->xmax = bbox->xmax;
- histo->ymax = bbox->ymax;
-
- histo->avgFeatureArea = 0;
-
- histo->boxesPerSide = boxesPerSide;
-
- for (t=0;t<boxesPerSide*boxesPerSide; t++)
- {
- histo->value[t] = 0;
- }
-
- /*elog(NOTICE,"create_lwhistogram2d returning");*/
-
- PG_RETURN_POINTER(histo);
-}
-
-/*
- * build_histogram2d (LWHISTOGRAM2D, tablename, columnname)
- * executes the SPI 'SELECT box3d(columnname) FROM tablename'
- * and sticks all the results in the histogram
- */
-PG_FUNCTION_INFO_V1(build_lwhistogram2d);
-Datum build_lwhistogram2d(PG_FUNCTION_ARGS)
-{
- LWHISTOGRAM2D *histo = (LWHISTOGRAM2D *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- char *tablename, *columnname;
- LWHISTOGRAM2D *result;
- int SPIcode;
- char sql[1000];
- SPITupleTable *tuptable;
- TupleDesc tupdesc ;
- int ntuples,t;
- Datum datum;
- bool isnull;
- HeapTuple tuple ;
- BOX2DFLOAT4 *box;
- double box_area, area_intersect, cell_area;
- int x_idx_min, x_idx_max;
- int y_idx_min, y_idx_max;
- double xmin,ymin, xmax,ymax;
- double intersect_x, intersect_y;
- int x,y;
- int total;
- double sum_area;
- int sum_area_numb;
-
- double sum_area_new = 0;
- int sum_area_numb_new =0;
- int bump=0;
-
- int tuplimit = 500000; /* No. of tuples returned on each cursor fetch */
- bool moredata;
- void *SPIplan;
- void *SPIportal;
-
- /*elog(NOTICE,"build_lwhistogram2d called");*/
-
- xmin = histo->xmin;
- ymin = histo->ymin;
- xmax = histo->xmax;
- ymax = histo->ymax;
-
- POSTGIS_DEBUGF(3, " build_histogram2d: histogram extent = %g %g, %g %g",
- histo->xmin, histo->ymin, histo->xmax, histo->ymax);
-
- result = (LWHISTOGRAM2D *) malloc(histo->size);
- memcpy(result,histo,histo->size);
-
-
- total = 0;
- for(t=0;t<histo->boxesPerSide*histo->boxesPerSide;t++)
- {
- total+=histo->value[t];
- }
-
-
-
- sum_area = histo->avgFeatureArea * total;
- sum_area_numb = total;
-
-
-
- tablename = DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(PG_GETARG_DATUM(1))));
-
- columnname = DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(PG_GETARG_DATUM(2))));
-
- POSTGIS_DEBUGF(3, "Start build_histogram2d with %i items already existing", sum_area_numb);
- POSTGIS_DEBUGF(3, "table=\"%s\", column = \"%s\"", tablename, columnname);
-
- SPIcode = SPI_connect();
-
- if (SPIcode != SPI_OK_CONNECT)
- {
- elog(ERROR,"build_histogram2d: couldnt open a connection to SPI");
- PG_RETURN_NULL() ;
- }
-
-
- sprintf(sql,"SELECT box2d(\"%s\") FROM \"%s\"",columnname,tablename);
- /*elog(NOTICE,"executing %s",sql);*/
-
- SPIplan = SPI_prepare(sql, 0, NULL);
- if (SPIplan == NULL)
- {
- elog(ERROR,"build_histogram2d: couldnt create query plan via SPI");
- PG_RETURN_NULL() ;
- }
-
-#if POSTGIS_PGSQL_VERSION >= 80
- SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, 1);
-#else
- SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL);
-#endif
- if (SPIportal == NULL)
- {
- elog(ERROR,"build_histogram2d: couldn't create cursor via SPI");
- PG_RETURN_NULL() ;
- }
-
-
- moredata = TRUE;
- while (moredata==TRUE)
- {
-
-
- POSTGIS_DEBUG(3, "about to fetch...");
-
- SPI_cursor_fetch(SPIportal, TRUE, tuplimit);
-
- ntuples = SPI_processed;
-
- POSTGIS_DEBUGF(3, "processing %d records", ntuples);
-
- if (ntuples > 0) {
-
- tuptable = SPI_tuptable;
- tupdesc = SPI_tuptable->tupdesc;
-
- cell_area = ( (xmax-xmin)*(ymax-ymin)/(histo->boxesPerSide*histo->boxesPerSide) );
-
- for (t=0;t<ntuples;t++)
- {
- tuple = tuptable->vals[t];
- datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
- if (!(isnull))
- {
- box = (BOX2DFLOAT4 *)DatumGetPointer(datum);
- box_area = (box->xmax-box->xmin)*(box->ymax-box->ymin);
-
- sum_area_new += box_area;
- sum_area_numb_new ++;
-
- if (box_area > cell_area )
- box_area = cell_area;
- if (box_area<0)
- box_area =0; /* for precision! */
-
- /* check to see which boxes this intersects */
- x_idx_min = (box->xmin-xmin)/(xmax-xmin)*histo->boxesPerSide;
- if (x_idx_min <0)
- x_idx_min = 0;
- if (x_idx_min >= histo->boxesPerSide)
- x_idx_min = histo->boxesPerSide-1;
- y_idx_min = (box->ymin-ymin)/(ymax-ymin)*histo->boxesPerSide;
- if (y_idx_min <0)
- y_idx_min = 0;
- if (y_idx_min >= histo->boxesPerSide)
- y_idx_min = histo->boxesPerSide-1;
-
- x_idx_max = (box->xmax-xmin)/(xmax-xmin)*histo->boxesPerSide;
- if (x_idx_max <0)
- x_idx_max = 0;
- if (x_idx_max >= histo->boxesPerSide)
- x_idx_max = histo->boxesPerSide-1;
- y_idx_max = (box->ymax-ymin)/(ymax-ymin)*histo->boxesPerSide ;
- if (y_idx_max <0)
- y_idx_max = 0;
- if (y_idx_max >= histo->boxesPerSide)
- y_idx_max = histo->boxesPerSide-1;
-
- /*
- * the {x,y}_idx_{min,max} define the grid squares that the box intersects
- * if the area of the intersect between the box and the grid square > 5% of
- */
-
- POSTGIS_DEBUGF(3, "box is : (%.15g,%.15g to %.15g,%.15g)",box->xmin,box->ymin, box->xmax, box->ymax);
- POSTGIS_DEBUGF(3, " search is in x: %i to %i y: %i to %i",x_idx_min, x_idx_max, y_idx_min,y_idx_max);
-
- for (y= y_idx_min; y<=y_idx_max;y++)
- {
- for (x=x_idx_min;x<= x_idx_max;x++)
- {
- intersect_x = LW_MIN(box->xmax, xmin+ (x+1) * (xmax-xmin)/histo->boxesPerSide ) - LW_MAX(box->xmin, xmin + x*(xmax-xmin)/histo->boxesPerSide ) ;
-
- intersect_y = LW_MIN(box->ymax, ymin+ (y+1) * (ymax-ymin)/histo->boxesPerSide ) - LW_MAX(box->ymin, ymin+ y*(ymax-ymin)/histo->boxesPerSide ) ;
-
- /* for a point, intersect_x=0, intersect_y=0, box_area =0*/
- POSTGIS_DEBUGF(3, "x=%i,y=%i, intersect_x= %.15g, intersect_y = %.15g",x,y,intersect_x,intersect_y);
-
- if ( (intersect_x>=0) && (intersect_y>=0) )
- {
- area_intersect = intersect_x*intersect_y;
- if (area_intersect >= box_area*0.05)
- {
- POSTGIS_DEBUG(3, "bump");
-
- bump++;
- result->value[x+y*histo->boxesPerSide]++;
- }
- }
- }
- } /* End of y */
-
- } /* End isnull */
-
- } /* End of for loop */
-
- /*
- * Free all the results after each fetch, otherwise all tuples stay
- * in memory until the end of the table...
- */
- SPI_freetuptable(tuptable);
-
- } else {
- moredata = FALSE;
- } /* End of if ntuples > 0 */
-
- } /* End of while loop */
-
-
- /* Close the cursor */
- SPI_cursor_close(SPIportal);
-
- SPIcode =SPI_finish();
- if (SPIcode != SPI_OK_FINISH )
- {
- elog(ERROR,"build_histogram2d: couldnt disconnect from SPI");
- PG_RETURN_NULL() ;
- }
-
- POSTGIS_DEBUG(3, "finishing up build_histogram2d ");
-
- /*pfree(tablename);*/
- /*pfree(columnname);*/
-
- total = 0;
- for(t=0;t<histo->boxesPerSide*histo->boxesPerSide;t++)
- {
- total+=result->value[t];
- }
-
- POSTGIS_DEBUGF(3, "histogram finishes with %i items in it - acutally added %i rows and %i bumps\n",total,sum_area_numb_new,bump);
- POSTGIS_DEBUG(3, "done build_histogram2d ");
-
-
- /* re-calculate statistics on avg bbox size */
- if (sum_area_numb_new >0)
- result->avgFeatureArea = (sum_area_new+sum_area)/((double)(sum_area_numb_new+sum_area_numb));
-
- PG_RETURN_POINTER(result) ;
-}
-/*
- * explode_lwhistogram2d(histogram2d, tablename::text)
- * executes CREATE TABLE tablename (the_geom geometry, id int, hits int, percent float)
- * then populates it
- * DOES NOT UPDATE GEOMETRY_COLUMNS
- */
-PG_FUNCTION_INFO_V1(explode_lwhistogram2d);
-Datum explode_lwhistogram2d(PG_FUNCTION_ARGS)
-{
- LWHISTOGRAM2D *histo = (LWHISTOGRAM2D *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- char *tablename;
- char sql[1000];
- char geom[1000];
- int t;
- int total;
- double cellx,celly;
- int x,y;
- int SPIcode;
-
- cellx = (histo->xmax-histo->xmin)/histo->boxesPerSide;
- celly = (histo->ymax-histo->ymin)/histo->boxesPerSide;
-
- tablename = DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(PG_GETARG_DATUM(1))));
-
- total = 0;
- for(t=0;t<histo->boxesPerSide*histo->boxesPerSide;t++)
- {
- total+=histo->value[t];
- }
- if (total==0)
- total=1;
-
- SPIcode = SPI_connect();
- if (SPIcode != SPI_OK_CONNECT)
- {
- elog(ERROR,"build_histogram2d: couldnt open a connection to SPI");
- PG_RETURN_NULL() ;
-
- }
-
- sprintf(sql,"CREATE TABLE %s (the_geom geometry, id int, hits int, percent float)",tablename);
-
- SPIcode = SPI_exec(sql, 2147483640 ); /* max signed int32 */
-
- if (SPIcode != SPI_OK_UTILITY )
- {
- elog(ERROR,"explode_histogram2d: couldnt create table");
- PG_RETURN_NULL() ;
- }
- t=0;
- for(y=0;y<histo->boxesPerSide;y++)
- {
- for(x=0;x<histo->boxesPerSide;x++)
- {
-
- sprintf(geom,"POLYGON((%.15g %.15g, %.15g %.15g, %.15g %.15g, %.15g %.15g, %.15g %.15g ))",
- histo->xmin + x*cellx, histo->ymin+y*celly,
- histo->xmin + (x)*cellx, histo->ymin+ (y+1)*celly,
- histo->xmin + (x+1)*cellx, histo->ymin+ (y+1)*celly,
- histo->xmin + (x+1)*cellx, histo->ymin+y*celly,
- histo->xmin + x*cellx, histo->ymin+y*celly
- );
- sprintf(sql,"INSERT INTO %s VALUES('%s'::geometry,%i,%i,%.15g)",tablename,geom,t,histo->value[t],histo->value[t]/((double)total)*100.0);
- t++;
- SPIcode = SPI_exec(sql, 2147483640 ); /* max signed int32 */
- if (SPIcode != SPI_OK_INSERT )
- {
- elog(ERROR,"explode_histogram2d: couldnt insert into");
- PG_RETURN_NULL() ;
- }
- }
- }
-
- SPIcode =SPI_finish();
- if (SPIcode != SPI_OK_FINISH )
- {
- elog(ERROR,"build_histogram2d: couldnt disconnect from SPI");
- PG_RETURN_NULL() ;
- }
-
- PG_RETURN_POINTER(histo) ;
-}
-
-/*
- * estimate_histogram2d(histogram2d, box2d)
- * returns a % estimate of the # of features that will be returned by that box query
- *
- * For each grid cell that intersects the query box
- * Calculate area of intersection (AOI)
- * IF AOI < avgFeatureArea THEN set AOI = avgFeatureArea
- * SUM AOI/area-of-cell*value-of-cell
- *
- * change : instead of avgFeatureArea, use avgFeatureArea or 10% of a grid cell (whichever is smaller)
- */
-PG_FUNCTION_INFO_V1(estimate_lwhistogram2d);
-Datum estimate_lwhistogram2d(PG_FUNCTION_ARGS)
-{
- LWHISTOGRAM2D *histo = (LWHISTOGRAM2D *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- BOX2DFLOAT4 *box = (BOX2DFLOAT4 *) PG_GETARG_POINTER(1);
- double box_area;
- int x_idx_min, x_idx_max, y_idx_min, y_idx_max;
- double intersect_x, intersect_y, AOI;
- int x,y;
- double xmin,ymin,xmax,ymax;
- int32 result_sum;
- double cell_area;
- int total,t;
- double avg_feature_size;
-
-
-
- result_sum = 0;
- xmin = histo->xmin;
- ymin = histo->ymin;
- xmax = histo->xmax;
- ymax = histo->ymax;
-
- cell_area = ( (xmax-xmin)*(ymax-ymin)/(histo->boxesPerSide*histo->boxesPerSide) );
-
- avg_feature_size = histo->avgFeatureArea;
- if ( avg_feature_size > cell_area*0.1)
- {
- avg_feature_size = cell_area*0.1;
- }
-
-
- POSTGIS_DEBUG(3, "start estimate_histogram2d: ");
- POSTGIS_DEBUGF(3, "box is : (%.15g,%.15g to %.15g,%.15g)",box->xmin, box->ymin, box->xmax, box->ymax);
-
- box_area = (box->xmax-box->xmin)*(box->ymax-box->ymin);
-
- if (box_area<0) box_area = 0; /* for precision! */
-
- /*
- * check to see which boxes this intersects
- */
- x_idx_min = (box->xmin-xmin)/(xmax-xmin)*histo->boxesPerSide;
- if (x_idx_min <0) x_idx_min = 0;
- if (x_idx_min >= histo->boxesPerSide)
- x_idx_min = histo->boxesPerSide-1;
- y_idx_min = (box->ymin-ymin)/(ymax-ymin)*histo->boxesPerSide;
- if (y_idx_min <0) y_idx_min = 0;
- if (y_idx_min >= histo->boxesPerSide)
- y_idx_min = histo->boxesPerSide-1;
-
- x_idx_max = (box->xmax-xmin)/(xmax-xmin)*histo->boxesPerSide;
- if (x_idx_max <0) x_idx_max = 0;
- if (x_idx_max >= histo->boxesPerSide)
- x_idx_max = histo->boxesPerSide-1;
- y_idx_max = (box->ymax-ymin)/(ymax-ymin)*histo->boxesPerSide ;
- if (y_idx_max <0) y_idx_max = 0;
- if (y_idx_max >= histo->boxesPerSide)
- y_idx_max = histo->boxesPerSide-1;
-
- /* The {x,y}_idx_{min,max} define the grid squares that the box intersects */
-
- POSTGIS_DEBUGF(3, " search is in x: %i to %i y: %i to %i",x_idx_min, x_idx_max, y_idx_min,y_idx_max);
-
- for (y= y_idx_min; y<=y_idx_max;y++)
- {
- for (x=x_idx_min;x<= x_idx_max;x++)
- {
- intersect_x = LW_MIN(box->xmax, xmin+ (x+1) * (xmax-xmin)/histo->boxesPerSide ) - LW_MAX(box->xmin, xmin+ x*(xmax-xmin)/histo->boxesPerSide ) ;
- intersect_y = LW_MIN(box->ymax, ymin+ (y+1) * (ymax-ymin)/histo->boxesPerSide ) - LW_MAX(box->ymin, ymin+ y*(ymax-ymin)/histo->boxesPerSide ) ;
-
-/* for a point, intersect_x=0, intersect_y=0, box_area =0 */
-/* elog(NOTICE,"x=%i,y=%i, intersect_x= %.15g, intersect_y = %.15g",x,y,intersect_x,intersect_y); */
- if ( (intersect_x>=0) && (intersect_y>=0) )
- {
- AOI = intersect_x*intersect_y;
- if (AOI< avg_feature_size)
- AOI = avg_feature_size;
- result_sum += AOI/cell_area *
- histo->value[x+y*histo->boxesPerSide];
- }
- }
- }
- total = 0;
- for(t=0;t<histo->boxesPerSide*histo->boxesPerSide;t++)
- {
- total+=histo->value[t];
- }
-
- if ( (histo->avgFeatureArea <=0) && (box_area <=0) )
- PG_RETURN_FLOAT8(1.0/((double)(total)));
- else
- PG_RETURN_FLOAT8(result_sum/((double)total));
-
-}
-
-
-#if ! REALLY_DO_JOINSEL || POSTGIS_PGSQL_VERSION < 80
+#if ! REALLY_DO_JOINSEL
/*
* JOIN selectivity in the GiST && operator
* for all PG versions
PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_JOINSEL);
}
-#else /* REALLY_DO_JOINSEL && POSTGIS_PGSQL_VERSION >= 80 */
+#else /* REALLY_DO_JOINSEL */
int calculate_column_intersection(BOX2DFLOAT4 *search_box, GEOM_STATS *geomstats1, GEOM_STATS *geomstats2);
PG_FUNCTION_INFO_V1(LWGEOM_gist_joinsel);
Datum LWGEOM_gist_joinsel(PG_FUNCTION_ARGS)
{
-#if POSTGIS_PGSQL_VERSION < 81
- Query *root = (Query *) PG_GETARG_POINTER(0);
-#else
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
-#endif
+
/* Oid operator = PG_GETARG_OID(1); */
List *args = (List *) PG_GETARG_POINTER(2);
JoinType jointype = (JoinType) PG_GETARG_INT16(3);
var1 = (Var *)arg1;
var2 = (Var *)arg2;
-#if POSTGIS_PGSQL_VERSION < 81
- relid1 = getrelid(var1->varno, root->rtable);
- relid2 = getrelid(var2->varno, root->rtable);
-#else
+
relid1 = getrelid(var1->varno, root->parse->rtable);
relid2 = getrelid(var2->varno, root->parse->rtable);
-#endif
POSTGIS_DEBUGF(3, "Working with relations oids: %d %d", relid1, relid2);
/**************************** FROM POSTGIS ****************/
-#if POSTGIS_PGSQL_VERSION < 80
-/*
- * get_restriction_var
- * Examine the args of a restriction clause to see if it's of the
- * form (var op something) or (something op var). If so, extract
- * and return the var and the other argument.
- *
- * Inputs:
- * args: clause argument list
- * varRelid: see specs for restriction selectivity functions
- *
- * Outputs: (these are set only if TRUE is returned)
- * *var: gets Var node
- * *other: gets other clause argument
- * *varonleft: set TRUE if var is on the left, FALSE if on the right
- *
- * Returns TRUE if a Var is identified, otherwise FALSE.
- */
-static bool
-get_restriction_var(List *args, int varRelid, Var **var,
- Node **other, bool *varonleft)
-{
- Node *left, *right;
-
- if (length(args) != 2) return false;
-
- left = (Node *) lfirst(args);
- right = (Node *) lsecond(args);
-
- /* Ignore any binary-compatible relabeling */
-
- if (IsA(left, RelabelType))
- left = (Node *)((RelabelType *) left)->arg;
- if (IsA(right, RelabelType))
- right = (Node *)((RelabelType *) right)->arg;
-
- /* Look for the var */
-
- if (IsA(left, Var) &&
- (varRelid == 0 || varRelid == ((Var *) left)->varno))
- {
- *var = (Var *) left;
- *other = right;
- *varonleft = true;
- }
- else if (IsA(right, Var) &&
- (varRelid == 0 || varRelid == ((Var *) right)->varno))
- {
- *var = (Var *) right;
- *other = left;
- *varonleft = false;
- }
- else
- {
- /* Duh, it's too complicated for me... */
- return false;
- }
-
- return true;
-}
-
-/* restriction in the GiST && operator */
-PG_FUNCTION_INFO_V1(LWGEOM_gist_sel);
-Datum LWGEOM_gist_sel(PG_FUNCTION_ARGS)
-{
- Query *root = (Query *) PG_GETARG_POINTER(0);
- List *args = (List *) PG_GETARG_POINTER(2);
- int varRelid = PG_GETARG_INT32(3);
- char *in;
- BOX2DFLOAT4 search_box;
- char sql[1000];
-
- SPITupleTable *tuptable;
- TupleDesc tupdesc ;
- HeapTuple tuple ;
-
- Datum datum;
- bool isnull;
-
- Var *var;
- Node *other;
- bool varonleft;
- Oid relid;
- int SPIcode;
-
- double myest;
-
-#ifndef POSTGIS_USE_STATS
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL);
-#endif
-
- POSTGIS_DEBUG(2, "LWGEOM_gist_sel was called");
-
- if (!get_restriction_var(args, varRelid, &var, &other, &varonleft))
- {
- POSTGIS_DEBUG(3, "get_restriction_var FAILED -returning early");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL);
- }
-
- relid = getrelid(var->varno, root->rtable);
- if (relid == InvalidOid)
- {
- POSTGIS_DEBUG(3, "getrelid FAILED (invalid oid) -returning early");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL);
- }
-
- POSTGIS_DEBUGF(3, "operator's oid = %i (this should be GEOMETRY && GEOMETRY)",operator);
- POSTGIS_DEBUGF(3, "relations' oid = %i (this should be the relation that the && is working on) ",relid);
- POSTGIS_DEBUGF(3, "varatt oid = %i (basically relations column #) ",var->varattno);
-
-
- if (IsA(other, Const) &&((Const *) other)->constisnull)
- {
- POSTGIS_DEBUG(3, "other operand of && is NULL - returning early");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL);
- }
-
- if (IsA(other, Const))
- {
- POSTGIS_DEBUGF(3, "The other side of the && is a constant with type (oid) = %i and length %i. This should be GEOMETRY with length -1 (variable length)",((Const*)other)->consttype,((Const*)other)->constlen);
-
- }
- else
- {
- POSTGIS_DEBUG(3, "the other side of && isnt a constant - returning early");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL);
- }
-
- /* get the BOX thats being searched in */
- in = (char *)PG_DETOAST_DATUM( ((Const*)other)->constvalue );
-
- if ( ! getbox2d_p(in+4, &search_box) )
- {
- /* empty geom */
- POSTGIS_DEBUG("search box is EMPTY");
-
- PG_RETURN_FLOAT8(0.0);
- }
-
- POSTGIS_DEBUGF(3, "requested search box is : (%.15g %.15g, %.15g %.15g)",search_box->xmin,search_box->ymin,search_box->xmax,search_box->ymax);
-
-
- SPIcode = SPI_connect();
- if (SPIcode != SPI_OK_CONNECT)
- {
- elog(NOTICE,"LWGEOM_gist_sel: couldnt open a connection to SPI:%i",SPIcode);
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL) ;
- }
-
- sprintf(sql,"SELECT stats FROM GEOMETRY_COLUMNS WHERE attrelid=%u AND varattnum=%i",relid,var->varattno);
-
- POSTGIS_DEBUGF(3, "sql:%s",sql);
-
- SPIcode = SPI_exec(sql, 1 );
- if (SPIcode != SPI_OK_SELECT )
- {
- SPI_finish();
- elog(NOTICE,"LWGEOM_gist_sel: couldnt execute sql via SPI");
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL) ;
- }
-
- if (SPI_processed !=1)
- {
- SPI_finish();
-
- POSTGIS_DEBUG(3, "LWGEOM_gist_sel: geometry_columns didnt return a unique value");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL) ;
- }
-
- tuptable = SPI_tuptable;
- tupdesc = SPI_tuptable->tupdesc;
- tuple = tuptable->vals[0];
- datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
- if (isnull)
- {
- SPI_finish();
-
- POSTGIS_DEBUG(3, "LWGEOM_gist_sel: geometry_columns returned a null histogram");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL) ;
- }
-
- POSTGIS_DEBUG(3, "LWGEOM_gist_sel: checking against estimate_histogram2d");
-
-
- /* now we have the histogram, and our search box - use the estimate_histogram2d(histo,box) to get the result! */
- myest = DatumGetFloat8( DirectFunctionCall2( estimate_lwhistogram2d, datum, PointerGetDatum(&search_box) ) );
-
- if ( (myest<0) || (myest!=myest) ) /* <0? or NaN? */
- {
- POSTGIS_DEBUG(3, "LWGEOM_gist_sel: got something crazy back from estimate_histogram2d");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL) ;
- }
-
- SPIcode =SPI_finish();
- if (SPIcode != SPI_OK_FINISH )
- {
- POSTGIS_DEBUG(3, "LWGEOM_gist_sel: couldnt disconnect from SPI");
-
- PG_RETURN_FLOAT8(DEFAULT_GEOMETRY_SEL) ;
- }
-
- POSTGIS_DEBUGF(3, "LWGEOM_gist_sel: finished, returning with %lf",myest);
-
- PG_RETURN_FLOAT8(myest);
-}
-
-/*
- * Return the extent of the table
- * looking at gathered statistics (or NULL if
- * no statistics have been gathered).
- */
-PG_FUNCTION_INFO_V1(LWGEOM_estimated_extent);
-Datum LWGEOM_estimated_extent(PG_FUNCTION_ARGS)
-{
- text *txnsp = NULL;
- text *txtbl = NULL;
- text *txcol = NULL;
- char *nsp = NULL;
- char *tbl = NULL;
- char *col = NULL;
- char *query;
- size_t querysize;
- SPITupleTable *tuptable;
- TupleDesc tupdesc ;
- HeapTuple tuple ;
- LWHISTOGRAM2D *histo;
- Datum datum;
- int SPIcode;
- bool isnull;
- BOX2DFLOAT4 *box;
-
- if ( PG_NARGS() == 3 )
- {
- txnsp = PG_GETARG_TEXT_P(0);
- nsp = palloc(VARSIZE(txnsp)+1);
- memcpy(nsp, VARDATA(txnsp), VARSIZE(txnsp)-VARHDRSZ);
- nsp[VARSIZE(txnsp)-VARHDRSZ]='\0';
-
- txtbl = PG_GETARG_TEXT_P(1);
- txcol = PG_GETARG_TEXT_P(2);
- }
- else if ( PG_NARGS() == 2 )
- {
- txtbl = PG_GETARG_TEXT_P(0);
- txcol = PG_GETARG_TEXT_P(1);
- }
- else
- {
- elog(ERROR, "estimated_extent() called with wrong number of arguments");
- PG_RETURN_NULL();
- }
-
- tbl = palloc(VARSIZE(txtbl)+1);
- memcpy(tbl, VARDATA(txtbl), VARSIZE(txtbl)-VARHDRSZ);
- tbl[VARSIZE(txtbl)-VARHDRSZ]='\0';
-
- col = palloc(VARSIZE(txcol)+1);
- memcpy(col, VARDATA(txcol), VARSIZE(txcol)-VARHDRSZ);
- col[VARSIZE(txcol)-VARHDRSZ]='\0';
-
- POSTGIS_DEBUG(2, "LWGEOM_estimated_extent called");
-
- /* Connect to SPI manager */
- SPIcode = SPI_connect();
- if (SPIcode != SPI_OK_CONNECT)
- {
- elog(ERROR, "LWGEOM_estimated_extent: couldnt open a connection to SPI");
- PG_RETURN_NULL() ;
- }
-
- querysize = strlen(tbl)+strlen(col)+256;
- if ( nsp )
- {
- querysize += strlen(nsp)+32;
- query = palloc(querysize);
- sprintf(query, "SELECT stats FROM geometry_columns WHERE f_table_schema = '%s' AND f_table_name = '%s' AND f_geometry_column = '%s'", nsp, tbl, col);
- }
- else
- {
- query = palloc(querysize);
- sprintf(query, "SELECT stats FROM geometry_columns WHERE f_table_name = '%s' AND f_geometry_column = '%s'", tbl, col);
- }
-
- POSTGIS_DEBUGF(4, " query: %s", query);
-
- SPIcode = SPI_exec(query, 1);
- if (SPIcode != SPI_OK_SELECT )
- {
- SPI_finish();
- elog(ERROR,"LWGEOM_estimated_extent: couldnt execute sql via SPI");
- PG_RETURN_NULL();
- }
- if (SPI_processed > 1)
- {
- SPI_finish();
- elog(NOTICE, " More then a single row (%d) in geometry_columns matches given schema/table/column specs", SPI_processed);
- PG_RETURN_NULL() ;
- }
- if (SPI_processed == 0)
- {
- SPI_finish();
-
- POSTGIS_DEBUG(3, " %d stat rows", SPI_processed);
-
- PG_RETURN_NULL() ;
- }
-
- tuptable = SPI_tuptable;
- tupdesc = SPI_tuptable->tupdesc;
- tuple = tuptable->vals[0];
- datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
- if (isnull)
- {
- SPI_finish();
-
- POSTGIS_DEBUG(3, " stats are NULL");
-
- PG_RETURN_NULL();
- }
-
- histo = (LWHISTOGRAM2D *)PG_DETOAST_DATUM(datum);
-
- POSTGIS_DEBUGF(3, " histogram extent = %g %g, %g %g", histo->xmin,
- histo->ymin, histo->xmax, histo->ymax);
-
- /*
- * Construct box2dfloat4.
- * Must allocate this in upper executor context
- * to keep it alive after SPI_finish().
- */
- box = SPI_palloc(sizeof(BOX2DFLOAT4));
-
- box->xmin = histo->xmin;
- box->ymin = histo->ymin;
- box->xmax = histo->xmax;
- box->ymax = histo->ymax;
-
- POSTGIS_DEBUGF(3, " histogram extent = %f %f, %f %f", box->xmin,
- box->ymin, box->xmax, box->ymax);
-
- SPIcode = SPI_finish();
- if (SPIcode != SPI_OK_FINISH )
- {
- elog(ERROR, "LWGEOM_estimated_extent: couldnt disconnect from SPI");
- }
-
- PG_RETURN_POINTER(box);
-}
-
-#else /* POSTGIS_PGSQL_VERSION >= 80 */
-
/*
* This function returns an estimate of the selectivity
* of a search_box looking at data in the GEOM_STATS
PG_FUNCTION_INFO_V1(LWGEOM_gist_sel);
Datum LWGEOM_gist_sel(PG_FUNCTION_ARGS)
{
-#if POSTGIS_PGSQL_VERSION < 81
- Query *root = (Query *) PG_GETARG_POINTER(0);
-#else
PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
-#endif
+
/* Oid operator = PG_GETARG_OID(1); */
List *args = (List *) PG_GETARG_POINTER(2);
/* int varRelid = PG_GETARG_INT32(3); */
* Get pg_statistic row
*/
-#if POSTGIS_PGSQL_VERSION < 81
-/* relid = getrelid(varRelid, root->rtable); */
- relid = getrelid(self->varno, root->rtable);
-#else
relid = getrelid(self->varno, root->parse->rtable);
-#endif
stats_tuple = SearchSysCache(STATRELATT, ObjectIdGetDatum(relid), Int16GetDatum(self->varattno), 0, 0);
if ( ! stats_tuple )
}
-#endif /* POSTGIS_PGSQL_VERSION >= 80 */
/**********************************************************************