PostGIS  2.2.8dev-r@@SVN_REVISION@@

◆ RASTER_histogramCoverage()

Datum RASTER_histogramCoverage ( PG_FUNCTION_ARGS  )

Definition at line 1194 of file rtpg_statistics.c.

References ovdump::band, genraster::count, rt_bandstats_t::count, rt_histogram_t::count, rtpg_summarystats_arg_t::exclude_nodata_value, FALSE, FLT_EQ, rt_histogram_t::max, MAX_DBL_CHARLEN, MAX_INT_CHARLEN, rt_histogram_t::min, rt_histogram_t::percent, PG_FUNCTION_INFO_V1(), POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, RASTER_quantile(), rt_band_destroy(), rt_band_get_histogram(), rt_band_get_summary_stats(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_get_num_bands(), rtpg_summarystats_arg_t::sample, rtgdalraster::sql, rtpg_summarystats_arg_t::stats, and TRUE.

Referenced by RASTER_histogram().

1195 {
1196  FuncCallContext *funcctx;
1197  TupleDesc tupdesc;
1198 
1199  int i;
1200  rt_histogram covhist = NULL;
1201  rt_histogram covhist2;
1202  int call_cntr;
1203  int max_calls;
1204 
1205  POSTGIS_RT_DEBUG(3, "RASTER_histogramCoverage: Starting");
1206 
1207  /* first call of function */
1208  if (SRF_IS_FIRSTCALL()) {
1209  MemoryContext oldcontext;
1210 
1211  text *tablenametext = NULL;
1212  char *tablename = NULL;
1213  text *colnametext = NULL;
1214  char *colname = NULL;
1215  int32_t bandindex = 1;
1216  bool exclude_nodata_value = TRUE;
1217  double sample = 0;
1218  uint32_t bin_count = 0;
1219  double *bin_width = NULL;
1220  uint32_t bin_width_count = 0;
1221  double width = 0;
1222  bool right = FALSE;
1223  uint32_t count;
1224 
1225  int len = 0;
1226  char *sql = NULL;
1227  char *tmp = NULL;
1228  double min = 0;
1229  double max = 0;
1230  int spi_result;
1231  Portal portal;
1232  SPITupleTable *tuptable = NULL;
1233  HeapTuple tuple;
1234  Datum datum;
1235  bool isNull = FALSE;
1236 
1237  rt_pgraster *pgraster = NULL;
1238  rt_raster raster = NULL;
1239  rt_band band = NULL;
1240  int num_bands = 0;
1241  rt_bandstats stats = NULL;
1242  rt_histogram hist;
1243  uint64_t sum = 0;
1244 
1245  int j;
1246  int n;
1247 
1248  ArrayType *array;
1249  Oid etype;
1250  Datum *e;
1251  bool *nulls;
1252  int16 typlen;
1253  bool typbyval;
1254  char typalign;
1255 
1256  POSTGIS_RT_DEBUG(3, "RASTER_histogramCoverage: first call of function");
1257 
1258  /* create a function context for cross-call persistence */
1259  funcctx = SRF_FIRSTCALL_INIT();
1260 
1261  /* switch to memory context appropriate for multiple function calls */
1262  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1263 
1264  /* tablename is null, return null */
1265  if (PG_ARGISNULL(0)) {
1266  elog(NOTICE, "Table name must be provided");
1267  MemoryContextSwitchTo(oldcontext);
1268  SRF_RETURN_DONE(funcctx);
1269  }
1270  tablenametext = PG_GETARG_TEXT_P(0);
1271  tablename = text_to_cstring(tablenametext);
1272  if (!strlen(tablename)) {
1273  elog(NOTICE, "Table name must be provided");
1274  MemoryContextSwitchTo(oldcontext);
1275  SRF_RETURN_DONE(funcctx);
1276  }
1277  POSTGIS_RT_DEBUGF(3, "RASTER_histogramCoverage: tablename = %s", tablename);
1278 
1279  /* column name is null, return null */
1280  if (PG_ARGISNULL(1)) {
1281  elog(NOTICE, "Column name must be provided");
1282  MemoryContextSwitchTo(oldcontext);
1283  SRF_RETURN_DONE(funcctx);
1284  }
1285  colnametext = PG_GETARG_TEXT_P(1);
1286  colname = text_to_cstring(colnametext);
1287  if (!strlen(colname)) {
1288  elog(NOTICE, "Column name must be provided");
1289  MemoryContextSwitchTo(oldcontext);
1290  SRF_RETURN_DONE(funcctx);
1291  }
1292  POSTGIS_RT_DEBUGF(3, "RASTER_histogramCoverage: colname = %s", colname);
1293 
1294  /* band index is 1-based */
1295  if (!PG_ARGISNULL(2))
1296  bandindex = PG_GETARG_INT32(2);
1297 
1298  /* exclude_nodata_value flag */
1299  if (!PG_ARGISNULL(3))
1300  exclude_nodata_value = PG_GETARG_BOOL(3);
1301 
1302  /* sample % */
1303  if (!PG_ARGISNULL(4)) {
1304  sample = PG_GETARG_FLOAT8(4);
1305  if (sample < 0 || sample > 1) {
1306  elog(NOTICE, "Invalid sample percentage (must be between 0 and 1). Returning NULL");
1307  MemoryContextSwitchTo(oldcontext);
1308  SRF_RETURN_DONE(funcctx);
1309  }
1310  else if (FLT_EQ(sample, 0.0))
1311  sample = 1;
1312  }
1313  else
1314  sample = 1;
1315 
1316  /* bin_count */
1317  if (!PG_ARGISNULL(5)) {
1318  bin_count = PG_GETARG_INT32(5);
1319  if (bin_count < 1) bin_count = 0;
1320  }
1321 
1322  /* bin_width */
1323  if (!PG_ARGISNULL(6)) {
1324  array = PG_GETARG_ARRAYTYPE_P(6);
1325  etype = ARR_ELEMTYPE(array);
1326  get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1327 
1328  switch (etype) {
1329  case FLOAT4OID:
1330  case FLOAT8OID:
1331  break;
1332  default:
1333  MemoryContextSwitchTo(oldcontext);
1334  elog(ERROR, "RASTER_histogramCoverage: Invalid data type for width");
1335  SRF_RETURN_DONE(funcctx);
1336  break;
1337  }
1338 
1339  deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1340  &nulls, &n);
1341 
1342  bin_width = palloc(sizeof(double) * n);
1343  for (i = 0, j = 0; i < n; i++) {
1344  if (nulls[i]) continue;
1345 
1346  switch (etype) {
1347  case FLOAT4OID:
1348  width = (double) DatumGetFloat4(e[i]);
1349  break;
1350  case FLOAT8OID:
1351  width = (double) DatumGetFloat8(e[i]);
1352  break;
1353  }
1354 
1355  if (width < 0 || FLT_EQ(width, 0.0)) {
1356  elog(NOTICE, "Invalid value for width (must be greater than 0). Returning NULL");
1357  pfree(bin_width);
1358  MemoryContextSwitchTo(oldcontext);
1359  SRF_RETURN_DONE(funcctx);
1360  }
1361 
1362  bin_width[j] = width;
1363  POSTGIS_RT_DEBUGF(5, "bin_width[%d] = %f", j, bin_width[j]);
1364  j++;
1365  }
1366  bin_width_count = j;
1367 
1368  if (j < 1) {
1369  pfree(bin_width);
1370  bin_width = NULL;
1371  }
1372  }
1373 
1374  /* right */
1375  if (!PG_ARGISNULL(7))
1376  right = PG_GETARG_BOOL(7);
1377 
1378  /* connect to database */
1379  spi_result = SPI_connect();
1380  if (spi_result != SPI_OK_CONNECT) {
1381 
1382  if (bin_width_count) pfree(bin_width);
1383 
1384  MemoryContextSwitchTo(oldcontext);
1385  elog(ERROR, "RASTER_histogramCoverage: Cannot connect to database using SPI");
1386  SRF_RETURN_DONE(funcctx);
1387  }
1388 
1389  /* coverage stats */
1390  len = sizeof(char) * (strlen("SELECT min, max FROM _st_summarystats('','',,::boolean,)") + strlen(tablename) + strlen(colname) + (MAX_INT_CHARLEN * 2) + MAX_DBL_CHARLEN + 1);
1391  sql = (char *) palloc(len);
1392  if (NULL == sql) {
1393 
1394  if (SPI_tuptable) SPI_freetuptable(tuptable);
1395  SPI_finish();
1396 
1397  if (bin_width_count) pfree(bin_width);
1398 
1399  MemoryContextSwitchTo(oldcontext);
1400  elog(ERROR, "RASTER_histogramCoverage: Cannot allocate memory for sql");
1401  SRF_RETURN_DONE(funcctx);
1402  }
1403 
1404  /* get stats */
1405  snprintf(sql, len, "SELECT min, max FROM _st_summarystats('%s','%s',%d,%d::boolean,%f)", tablename, colname, bandindex, (exclude_nodata_value ? 1 : 0), sample);
1406  POSTGIS_RT_DEBUGF(3, "RASTER_histogramCoverage: %s", sql);
1407  spi_result = SPI_execute(sql, TRUE, 0);
1408  pfree(sql);
1409  if (spi_result != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
1410 
1411  if (SPI_tuptable) SPI_freetuptable(tuptable);
1412  SPI_finish();
1413 
1414  if (bin_width_count) pfree(bin_width);
1415 
1416  MemoryContextSwitchTo(oldcontext);
1417  elog(ERROR, "RASTER_histogramCoverage: Cannot get summary stats of coverage");
1418  SRF_RETURN_DONE(funcctx);
1419  }
1420 
1421  tupdesc = SPI_tuptable->tupdesc;
1422  tuptable = SPI_tuptable;
1423  tuple = tuptable->vals[0];
1424 
1425  tmp = SPI_getvalue(tuple, tupdesc, 1);
1426  if (NULL == tmp || !strlen(tmp)) {
1427 
1428  if (SPI_tuptable) SPI_freetuptable(tuptable);
1429  SPI_finish();
1430 
1431  if (bin_width_count) pfree(bin_width);
1432 
1433  MemoryContextSwitchTo(oldcontext);
1434  elog(ERROR, "RASTER_histogramCoverage: Cannot get summary stats of coverage");
1435  SRF_RETURN_DONE(funcctx);
1436  }
1437  min = strtod(tmp, NULL);
1438  POSTGIS_RT_DEBUGF(3, "RASTER_histogramCoverage: min = %f", min);
1439  pfree(tmp);
1440 
1441  tmp = SPI_getvalue(tuple, tupdesc, 2);
1442  if (NULL == tmp || !strlen(tmp)) {
1443 
1444  if (SPI_tuptable) SPI_freetuptable(tuptable);
1445  SPI_finish();
1446 
1447  if (bin_width_count) pfree(bin_width);
1448 
1449  MemoryContextSwitchTo(oldcontext);
1450  elog(ERROR, "RASTER_histogramCoverage: Cannot get summary stats of coverage");
1451  SRF_RETURN_DONE(funcctx);
1452  }
1453  max = strtod(tmp, NULL);
1454  POSTGIS_RT_DEBUGF(3, "RASTER_histogramCoverage: max = %f", max);
1455  pfree(tmp);
1456 
1457  /* iterate through rasters of coverage */
1458  /* create sql */
1459  len = sizeof(char) * (strlen("SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
1460  sql = (char *) palloc(len);
1461  if (NULL == sql) {
1462 
1463  if (SPI_tuptable) SPI_freetuptable(tuptable);
1464  SPI_finish();
1465 
1466  if (bin_width_count) pfree(bin_width);
1467 
1468  MemoryContextSwitchTo(oldcontext);
1469  elog(ERROR, "RASTER_histogramCoverage: Cannot allocate memory for sql");
1470  SRF_RETURN_DONE(funcctx);
1471  }
1472 
1473  /* get cursor */
1474  snprintf(sql, len, "SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
1475  POSTGIS_RT_DEBUGF(3, "RASTER_histogramCoverage: %s", sql);
1476  portal = SPI_cursor_open_with_args(
1477  "coverage",
1478  sql,
1479  0, NULL,
1480  NULL, NULL,
1481  TRUE, 0
1482  );
1483  pfree(sql);
1484 
1485  /* process resultset */
1486  SPI_cursor_fetch(portal, TRUE, 1);
1487  while (SPI_processed == 1 && SPI_tuptable != NULL) {
1488  tupdesc = SPI_tuptable->tupdesc;
1489  tuptable = SPI_tuptable;
1490  tuple = tuptable->vals[0];
1491 
1492  datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
1493  if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
1494 
1495  if (SPI_tuptable) SPI_freetuptable(tuptable);
1496  SPI_cursor_close(portal);
1497  SPI_finish();
1498 
1499  if (NULL != covhist) pfree(covhist);
1500  if (bin_width_count) pfree(bin_width);
1501 
1502  MemoryContextSwitchTo(oldcontext);
1503  elog(ERROR, "RASTER_histogramCoverage: Cannot get raster of coverage");
1504  SRF_RETURN_DONE(funcctx);
1505  }
1506  else if (isNull) {
1507  SPI_cursor_fetch(portal, TRUE, 1);
1508  continue;
1509  }
1510 
1511  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(datum);
1512 
1513  raster = rt_raster_deserialize(pgraster, FALSE);
1514  if (!raster) {
1515 
1516  if (SPI_tuptable) SPI_freetuptable(tuptable);
1517  SPI_cursor_close(portal);
1518  SPI_finish();
1519 
1520  if (NULL != covhist) pfree(covhist);
1521  if (bin_width_count) pfree(bin_width);
1522 
1523  MemoryContextSwitchTo(oldcontext);
1524  elog(ERROR, "RASTER_histogramCoverage: Cannot deserialize raster");
1525  SRF_RETURN_DONE(funcctx);
1526  }
1527 
1528  /* inspect number of bands*/
1529  num_bands = rt_raster_get_num_bands(raster);
1530  if (bandindex < 1 || bandindex > num_bands) {
1531  elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
1532 
1533  rt_raster_destroy(raster);
1534 
1535  if (SPI_tuptable) SPI_freetuptable(tuptable);
1536  SPI_cursor_close(portal);
1537  SPI_finish();
1538 
1539  if (NULL != covhist) pfree(covhist);
1540  if (bin_width_count) pfree(bin_width);
1541 
1542  MemoryContextSwitchTo(oldcontext);
1543  SRF_RETURN_DONE(funcctx);
1544  }
1545 
1546  /* get band */
1547  band = rt_raster_get_band(raster, bandindex - 1);
1548  if (!band) {
1549  elog(NOTICE, "Cannot find band at index %d. Returning NULL", bandindex);
1550 
1551  rt_raster_destroy(raster);
1552 
1553  if (SPI_tuptable) SPI_freetuptable(tuptable);
1554  SPI_cursor_close(portal);
1555  SPI_finish();
1556 
1557  if (NULL != covhist) pfree(covhist);
1558  if (bin_width_count) pfree(bin_width);
1559 
1560  MemoryContextSwitchTo(oldcontext);
1561  SRF_RETURN_DONE(funcctx);
1562  }
1563 
1564  /* we need the raw values, hence the non-zero parameter */
1565  stats = rt_band_get_summary_stats(band, (int) exclude_nodata_value, sample, 1, NULL, NULL, NULL);
1566 
1567  rt_band_destroy(band);
1568  rt_raster_destroy(raster);
1569 
1570  if (NULL == stats) {
1571  elog(NOTICE, "Cannot compute summary statistics for band at index %d. Returning NULL", bandindex);
1572 
1573  if (SPI_tuptable) SPI_freetuptable(tuptable);
1574  SPI_cursor_close(portal);
1575  SPI_finish();
1576 
1577  if (NULL != covhist) pfree(covhist);
1578  if (bin_width_count) pfree(bin_width);
1579 
1580  MemoryContextSwitchTo(oldcontext);
1581  SRF_RETURN_DONE(funcctx);
1582  }
1583 
1584  /* get histogram */
1585  if (stats->count > 0) {
1586  hist = rt_band_get_histogram(stats, bin_count, bin_width, bin_width_count, right, min, max, &count);
1587  pfree(stats);
1588  if (NULL == hist || !count) {
1589  elog(NOTICE, "Cannot compute histogram for band at index %d", bandindex);
1590 
1591  if (SPI_tuptable) SPI_freetuptable(tuptable);
1592  SPI_cursor_close(portal);
1593  SPI_finish();
1594 
1595  if (NULL != covhist) pfree(covhist);
1596  if (bin_width_count) pfree(bin_width);
1597 
1598  MemoryContextSwitchTo(oldcontext);
1599  SRF_RETURN_DONE(funcctx);
1600  }
1601 
1602  POSTGIS_RT_DEBUGF(3, "%d bins returned", count);
1603 
1604  /* coverage histogram */
1605  if (NULL == covhist) {
1606  covhist = (rt_histogram) SPI_palloc(sizeof(struct rt_histogram_t) * count);
1607  if (NULL == covhist) {
1608 
1609  pfree(hist);
1610  if (SPI_tuptable) SPI_freetuptable(tuptable);
1611  SPI_cursor_close(portal);
1612  SPI_finish();
1613 
1614  if (bin_width_count) pfree(bin_width);
1615 
1616  MemoryContextSwitchTo(oldcontext);
1617  elog(ERROR, "RASTER_histogramCoverage: Cannot allocate memory for histogram of coverage");
1618  SRF_RETURN_DONE(funcctx);
1619  }
1620 
1621  for (i = 0; i < count; i++) {
1622  sum += hist[i].count;
1623  covhist[i].count = hist[i].count;
1624  covhist[i].percent = 0;
1625  covhist[i].min = hist[i].min;
1626  covhist[i].max = hist[i].max;
1627  }
1628  }
1629  else {
1630  for (i = 0; i < count; i++) {
1631  sum += hist[i].count;
1632  covhist[i].count += hist[i].count;
1633  }
1634  }
1635 
1636  pfree(hist);
1637 
1638  /* assuming bin_count wasn't set, force consistency */
1639  if (bin_count <= 0) bin_count = count;
1640  }
1641 
1642  /* next record */
1643  SPI_cursor_fetch(portal, TRUE, 1);
1644  }
1645 
1646  if (SPI_tuptable) SPI_freetuptable(tuptable);
1647  SPI_cursor_close(portal);
1648  SPI_finish();
1649 
1650  if (bin_width_count) pfree(bin_width);
1651 
1652  /* finish percent of histogram */
1653  if (sum > 0) {
1654  for (i = 0; i < count; i++)
1655  covhist[i].percent = covhist[i].count / (double) sum;
1656  }
1657 
1658  /* Store needed information */
1659  funcctx->user_fctx = covhist;
1660 
1661  /* total number of tuples to be returned */
1662  funcctx->max_calls = count;
1663 
1664  /* Build a tuple descriptor for our result type */
1665  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
1666  ereport(ERROR, (
1667  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1668  errmsg(
1669  "function returning record called in context "
1670  "that cannot accept type record"
1671  )
1672  ));
1673  }
1674 
1675  BlessTupleDesc(tupdesc);
1676  funcctx->tuple_desc = tupdesc;
1677 
1678  MemoryContextSwitchTo(oldcontext);
1679  }
1680 
1681  /* stuff done on every call of the function */
1682  funcctx = SRF_PERCALL_SETUP();
1683 
1684  call_cntr = funcctx->call_cntr;
1685  max_calls = funcctx->max_calls;
1686  tupdesc = funcctx->tuple_desc;
1687  covhist2 = funcctx->user_fctx;
1688 
1689  /* do when there is more left to send */
1690  if (call_cntr < max_calls) {
1691  int values_length = 4;
1692  Datum values[values_length];
1693  bool nulls[values_length];
1694  HeapTuple tuple;
1695  Datum result;
1696 
1697  POSTGIS_RT_DEBUGF(3, "Result %d", call_cntr);
1698 
1699  memset(nulls, FALSE, sizeof(bool) * values_length);
1700 
1701  values[0] = Float8GetDatum(covhist2[call_cntr].min);
1702  values[1] = Float8GetDatum(covhist2[call_cntr].max);
1703  values[2] = Int64GetDatum(covhist2[call_cntr].count);
1704  values[3] = Float8GetDatum(covhist2[call_cntr].percent);
1705 
1706  /* build a tuple */
1707  tuple = heap_form_tuple(tupdesc, values, nulls);
1708 
1709  /* make the tuple into a datum */
1710  result = HeapTupleGetDatum(tuple);
1711 
1712  SRF_RETURN_NEXT(funcctx, result);
1713  }
1714  /* do when there is no more left */
1715  else {
1716  pfree(covhist2);
1717  SRF_RETURN_DONE(funcctx);
1718  }
1719 }
int rt_raster_get_num_bands(rt_raster raster)
Definition: rt_raster.c:372
uint32_t count
Definition: librtcore.h:2323
raster
Be careful!! Zeros function&#39;s input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
band
Definition: ovdump.py:57
#define FLT_EQ(x, y)
Definition: librtcore.h:2197
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition: rt_band.c:242
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:57
#define MAX_INT_CHARLEN
Definition: rtpostgis.h:68
double percent
Definition: librtcore.h:2338
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
int count
Definition: genraster.py:56
#define MAX_DBL_CHARLEN
Definition: rtpostgis.h:67
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
rt_bandstats rt_band_get_summary_stats(rt_band band, int exclude_nodata_value, double sample, int inc_vals, uint64_t *cK, double *cM, double *cQ)
Compute summary statistics for a band.
struct rt_histogram_t * rt_histogram
Definition: librtcore.h:163
#define FALSE
Definition: dbfopen.c:168
Struct definitions.
Definition: librtcore.h:2213
rt_histogram rt_band_get_histogram(rt_bandstats stats, int bin_count, double *bin_widths, int bin_widths_count, int right, double min, double max, uint32_t *rtn_count)
Count the distribution of data.
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:53
#define TRUE
Definition: dbfopen.c:169
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:717
uint32_t count
Definition: librtcore.h:2337
Here is the call graph for this function:
Here is the caller graph for this function: