PostGIS  3.2.2dev-r@@SVN_REVISION@@

◆ compute_gserialized_stats_mode()

static void compute_gserialized_stats_mode ( VacAttrStats *  stats,
AnalyzeAttrFetchFunc  fetchfunc,
int  sample_rows,
double  total_rows,
int  mode 
)
static

The gserialized_analyze_nd sets this function as a callback on the stats object when called by the ANALYZE command.

ANALYZE then gathers the requisite number of sample rows and then calls this function.

We could also pass stats->extra_data in from gserialized_analyze_nd (things like the column type or other stuff from the system catalogs) but so far we don't use that capability.

Our job is to build some statistics on the sample data for use by operator estimators.

We will populate an n-d histogram using the provided sample rows. The selectivity estimators (sel and joinsel) can then use the histogram

Definition at line 1380 of file gserialized_estimate.c.

1382 {
1383  MemoryContext old_context;
1384  int d, i; /* Counters */
1385  int notnull_cnt = 0; /* # not null rows in the sample */
1386  int null_cnt = 0; /* # null rows in the sample */
1387  int histogram_features = 0; /* # rows that actually got counted in the histogram */
1388 
1389  ND_STATS *nd_stats; /* Our histogram */
1390  size_t nd_stats_size; /* Size to allocate */
1391 
1392  double total_width = 0; /* # of bytes used by sample */
1393  double total_sample_volume = 0; /* Area/volume coverage of the sample */
1394  double total_cell_count = 0; /* # of cells in histogram affected by sample */
1395 
1396  ND_BOX sum; /* Sum of extents of sample boxes */
1397  ND_BOX avg; /* Avg of extents of sample boxes */
1398  ND_BOX stddev; /* StdDev of extents of sample boxes */
1399 
1400  const ND_BOX **sample_boxes; /* ND_BOXes for each of the sample features */
1401  ND_BOX sample_extent; /* Extent of the raw sample */
1402  int histo_size[ND_DIMS]; /* histogram nrows, ncols, etc */
1403  ND_BOX histo_extent; /* Spatial extent of the histogram */
1404  ND_BOX histo_extent_new; /* Temporary variable */
1405  int histo_cells_target; /* Number of cells we will shoot for, given the stats target */
1406  int histo_cells; /* Number of cells in the histogram */
1407  int histo_cells_new = 1; /* Temporary variable */
1408 
1409  int ndims = 2; /* Dimensionality of the sample */
1410  int histo_ndims = 0; /* Dimensionality of the histogram */
1411  double sample_distribution[ND_DIMS]; /* How homogeneous is distribution of sample in each axis? */
1412  double total_distribution; /* Total of sample_distribution */
1413 
1414  int stats_slot; /* What slot is this data going into? (2D vs ND) */
1415  int stats_kind; /* And this is what? (2D vs ND) */
1416 
1417  /* Initialize sum and stddev */
1418  nd_box_init(&sum);
1419  nd_box_init(&stddev);
1420  nd_box_init(&avg);
1421  nd_box_init(&histo_extent);
1422  nd_box_init(&histo_extent_new);
1423 
1424  /*
1425  * This is where gserialized_analyze_nd
1426  * should put its' custom parameters.
1427  */
1428  /* void *mystats = stats->extra_data; */
1429 
1430  POSTGIS_DEBUG(2, "compute_gserialized_stats called");
1431  POSTGIS_DEBUGF(3, " # sample_rows: %d", sample_rows);
1432  POSTGIS_DEBUGF(3, " estimate of total_rows: %.6g", total_rows);
1433 
1434  /*
1435  * We might need less space, but don't think
1436  * its worth saving...
1437  */
1438  sample_boxes = palloc(sizeof(ND_BOX*) * sample_rows);
1439 
1440  /*
1441  * First scan:
1442  * o read boxes
1443  * o find dimensionality of the sample
1444  * o find extent of the sample
1445  * o count null-infinite/not-null values
1446  * o compute total_width
1447  * o compute total features's box area (for avgFeatureArea)
1448  * o sum features box coordinates (for standard deviation)
1449  */
1450  for ( i = 0; i < sample_rows; i++ )
1451  {
1452  Datum datum;
1453  GBOX gbox = {0};
1454  ND_BOX *nd_box;
1455  bool is_null;
1456 
1457  datum = fetchfunc(stats, i, &is_null);
1458 
1459  /* Skip all NULLs. */
1460  if ( is_null )
1461  {
1462  POSTGIS_DEBUGF(4, " skipped null geometry %d", i);
1463  null_cnt++;
1464  continue;
1465  }
1466 
1467  /* Read the bounds from the gserialized. */
1468  if (LW_FAILURE == gserialized_datum_get_gbox_p(datum, &gbox))
1469  {
1470  /* Skip empties too. */
1471  POSTGIS_DEBUGF(3, " skipped empty geometry %d", i);
1472  continue;
1473  }
1474 
1475  /* If we're in 2D mode, zero out the higher dimensions for "safety" */
1476  if ( mode == 2 )
1477  gbox.zmin = gbox.zmax = gbox.mmin = gbox.mmax = 0.0;
1478 
1479  /* Check bounds for validity (finite and not NaN) */
1480  if ( ! gbox_is_valid(&gbox) )
1481  {
1482  POSTGIS_DEBUGF(3, " skipped infinite/nan geometry %d", i);
1483  continue;
1484  }
1485 
1486  /*
1487  * In N-D mode, set the ndims to the maximum dimensionality found
1488  * in the sample. Otherwise, leave at ndims == 2.
1489  */
1490  if ( mode != 2 )
1491  ndims = Max(gbox_ndims(&gbox), ndims);
1492 
1493  /* Convert gbox to n-d box */
1494  nd_box = palloc(sizeof(ND_BOX));
1495  nd_box_from_gbox(&gbox, nd_box);
1496 
1497  /* Cache n-d bounding box */
1498  sample_boxes[notnull_cnt] = nd_box;
1499 
1500  /* Initialize sample extent before merging first entry */
1501  if ( ! notnull_cnt )
1502  nd_box_init_bounds(&sample_extent);
1503 
1504  /* Add current sample to overall sample extent */
1505  nd_box_merge(nd_box, &sample_extent);
1506 
1507  /* How many bytes does this sample use? */
1508  total_width += toast_raw_datum_size(datum);
1509 
1510  /* Add bounds coordinates to sums for stddev calculation */
1511  for ( d = 0; d < ndims; d++ )
1512  {
1513  sum.min[d] += nd_box->min[d];
1514  sum.max[d] += nd_box->max[d];
1515  }
1516 
1517  /* Increment our "good feature" count */
1518  notnull_cnt++;
1519 
1520  /* Give backend a chance of interrupting us */
1521  vacuum_delay_point();
1522  }
1523 
1524  /*
1525  * We'll build a histogram having stats->attr->attstattarget cells
1526  * on each side, within reason... we'll use ndims*10000 as the
1527  * maximum number of cells.
1528  * Also, if we're sampling a relatively small table, we'll try to ensure that
1529  * we have an average of 5 features for each cell so the histogram isn't
1530  * so sparse.
1531  */
1532  histo_cells_target = (int)pow((double)(stats->attr->attstattarget), (double)ndims);
1533  histo_cells_target = Min(histo_cells_target, ndims * 10000);
1534  histo_cells_target = Min(histo_cells_target, (int)(total_rows/5));
1535  POSTGIS_DEBUGF(3, " stats->attr->attstattarget: %d", stats->attr->attstattarget);
1536  POSTGIS_DEBUGF(3, " target # of histogram cells: %d", histo_cells_target);
1537 
1538  /* If there's no useful features, we can't work out stats */
1539  if ( ! notnull_cnt )
1540  {
1541 #if POSTGIS_DEBUG_LEVEL > 0
1542  Oid relation_oid = stats->attr->attrelid;
1543  char *relation_name = get_rel_name(relation_oid);
1544  char *namespace = get_namespace_name(get_rel_namespace(relation_oid));
1545  elog(DEBUG1,
1546  "PostGIS: Unable to compute statistics for \"%s.%s.%s\": No non-null/empty features",
1547  namespace ? namespace : "(NULL)",
1548  relation_name ? relation_name : "(NULL)",
1549  stats->attr->attname.data);
1550 #endif /* POSTGIS_DEBUG_LEVEL > 0 */
1551  stats->stats_valid = false;
1552  return;
1553  }
1554 
1555  POSTGIS_DEBUGF(3, " sample_extent: %s", nd_box_to_json(&sample_extent, ndims));
1556 
1557  /*
1558  * Second scan:
1559  * o compute standard deviation
1560  */
1561  for ( d = 0; d < ndims; d++ )
1562  {
1563  /* Calculate average bounds values */
1564  avg.min[d] = sum.min[d] / notnull_cnt;
1565  avg.max[d] = sum.max[d] / notnull_cnt;
1566 
1567  /* Calculate standard deviation for this dimension bounds */
1568  for ( i = 0; i < notnull_cnt; i++ )
1569  {
1570  const ND_BOX *ndb = sample_boxes[i];
1571  stddev.min[d] += (ndb->min[d] - avg.min[d]) * (ndb->min[d] - avg.min[d]);
1572  stddev.max[d] += (ndb->max[d] - avg.max[d]) * (ndb->max[d] - avg.max[d]);
1573  }
1574  stddev.min[d] = sqrt(stddev.min[d] / notnull_cnt);
1575  stddev.max[d] = sqrt(stddev.max[d] / notnull_cnt);
1576 
1577  /* Histogram bounds for this dimension bounds is avg +/- SDFACTOR * stdev */
1578  histo_extent.min[d] = Max(avg.min[d] - SDFACTOR * stddev.min[d], sample_extent.min[d]);
1579  histo_extent.max[d] = Min(avg.max[d] + SDFACTOR * stddev.max[d], sample_extent.max[d]);
1580  }
1581 
1582  /*
1583  * Third scan:
1584  * o skip hard deviants
1585  * o compute new histogram box
1586  */
1587  nd_box_init_bounds(&histo_extent_new);
1588  for ( i = 0; i < notnull_cnt; i++ )
1589  {
1590  const ND_BOX *ndb = sample_boxes[i];
1591  /* Skip any hard deviants (boxes entirely outside our histo_extent */
1592  if ( ! nd_box_intersects(&histo_extent, ndb, ndims) )
1593  {
1594  POSTGIS_DEBUGF(4, " feature %d is a hard deviant, skipped", i);
1595  sample_boxes[i] = NULL;
1596  continue;
1597  }
1598  /* Expand our new box to fit all the other features. */
1599  nd_box_merge(ndb, &histo_extent_new);
1600  }
1601  /*
1602  * Expand the box slightly (1%) to avoid edge effects
1603  * with objects that are on the boundary
1604  */
1605  nd_box_expand(&histo_extent_new, 0.01);
1606  histo_extent = histo_extent_new;
1607 
1608  /*
1609  * How should we allocate our histogram cells to the
1610  * different dimensions? We can't do it by raw dimensional width,
1611  * because in x/y/z space, the z can have different units
1612  * from the x/y. Similarly for x/y/t space.
1613  * So, we instead calculate how much features overlap
1614  * each other in their dimension to figure out which
1615  * dimensions have useful selectivity characteristics (more
1616  * variability in density) and therefor would find
1617  * more cells useful (to distinguish between dense places and
1618  * homogeneous places).
1619  */
1620  nd_box_array_distribution(sample_boxes, notnull_cnt, &histo_extent, ndims,
1621  sample_distribution);
1622 
1623  /*
1624  * The sample_distribution array now tells us how spread out the
1625  * data is in each dimension, so we use that data to allocate
1626  * the histogram cells we have available.
1627  * At this point, histo_cells_target is the approximate target number
1628  * of cells.
1629  */
1630 
1631  /*
1632  * Some dimensions have basically a uniform distribution, we want
1633  * to allocate no cells to those dimensions, only to dimensions
1634  * that have some interesting differences in data distribution.
1635  * Here we count up the number of interesting dimensions
1636  */
1637  for ( d = 0; d < ndims; d++ )
1638  {
1639  if ( sample_distribution[d] > 0 )
1640  histo_ndims++;
1641  }
1642 
1643  if ( histo_ndims == 0 )
1644  {
1645  /* Special case: all our dimensions had low variability! */
1646  /* We just divide the cells up evenly */
1647  POSTGIS_DEBUG(3, " special case: no axes have variability");
1648  histo_cells_new = 1;
1649  for ( d = 0; d < ndims; d++ )
1650  {
1651  histo_size[d] = (int)pow((double)histo_cells_target, 1/(double)ndims);
1652  if ( ! histo_size[d] )
1653  histo_size[d] = 1;
1654  POSTGIS_DEBUGF(3, " histo_size[d]: %d", histo_size[d]);
1655  histo_cells_new *= histo_size[d];
1656  }
1657  POSTGIS_DEBUGF(3, " histo_cells_new: %d", histo_cells_new);
1658  }
1659  else
1660  {
1661  /*
1662  * We're going to express the amount of variability in each dimension
1663  * as a proportion of the total variability and allocate cells in that
1664  * dimension relative to that proportion.
1665  */
1666  POSTGIS_DEBUG(3, " allocating histogram axes based on axis variability");
1667  total_distribution = total_double(sample_distribution, ndims); /* First get the total */
1668  POSTGIS_DEBUGF(3, " total_distribution: %.8g", total_distribution);
1669  histo_cells_new = 1; /* For the number of cells in the final histogram */
1670  for ( d = 0; d < ndims; d++ )
1671  {
1672  if ( sample_distribution[d] == 0 ) /* Uninteresting dimensions don't get any room */
1673  {
1674  histo_size[d] = 1;
1675  }
1676  else /* Interesting dimension */
1677  {
1678  /* How does this dims variability compare to the total? */
1679  float edge_ratio = (float)sample_distribution[d] / (float)total_distribution;
1680  /*
1681  * Scale the target cells number by the # of dims and ratio,
1682  * then take the appropriate root to get the estimated number of cells
1683  * on this axis (eg, pow(0.5) for 2d, pow(0.333) for 3d, pow(0.25) for 4d)
1684  */
1685  histo_size[d] = (int)pow(histo_cells_target * histo_ndims * edge_ratio, 1/(double)histo_ndims);
1686  /* If something goes awry, just give this dim one slot */
1687  if ( ! histo_size[d] )
1688  histo_size[d] = 1;
1689  }
1690  histo_cells_new *= histo_size[d];
1691  }
1692  POSTGIS_DEBUGF(3, " histo_cells_new: %d", histo_cells_new);
1693  }
1694 
1695  /* Update histo_cells to the actual number of cells we need to allocate */
1696  histo_cells = histo_cells_new;
1697  POSTGIS_DEBUGF(3, " histo_cells: %d", histo_cells);
1698 
1699  /*
1700  * Create the histogram (ND_STATS) in the stats memory context
1701  */
1702  old_context = MemoryContextSwitchTo(stats->anl_context);
1703  nd_stats_size = sizeof(ND_STATS) + ((histo_cells - 1) * sizeof(float4));
1704  nd_stats = palloc(nd_stats_size);
1705  memset(nd_stats, 0, nd_stats_size); /* Initialize all values to 0 */
1706  MemoryContextSwitchTo(old_context);
1707 
1708  /* Initialize the #ND_STATS objects */
1709  nd_stats->ndims = ndims;
1710  nd_stats->extent = histo_extent;
1711  nd_stats->sample_features = sample_rows;
1712  nd_stats->table_features = total_rows;
1713  nd_stats->not_null_features = notnull_cnt;
1714  /* Copy in the histogram dimensions */
1715  for ( d = 0; d < ndims; d++ )
1716  nd_stats->size[d] = histo_size[d];
1717 
1718  /*
1719  * Fourth scan:
1720  * o fill histogram values with the proportion of
1721  * features' bbox overlaps: a feature's bvol
1722  * can fully overlap (1) or partially overlap
1723  * (fraction of 1) an histogram cell.
1724  *
1725  * Note that we are filling each cell with the "portion of
1726  * the feature's box that overlaps the cell". So, if we sum
1727  * up the values in the histogram, we could get the
1728  * histogram feature count.
1729  *
1730  */
1731  for ( i = 0; i < notnull_cnt; i++ )
1732  {
1733  const ND_BOX *nd_box;
1734  ND_IBOX nd_ibox;
1735  int at[ND_DIMS];
1736  int d;
1737  double num_cells = 0;
1738  double tmp_volume = 1.0;
1739  double min[ND_DIMS] = {0.0, 0.0, 0.0, 0.0};
1740  double max[ND_DIMS] = {0.0, 0.0, 0.0, 0.0};
1741  double cellsize[ND_DIMS] = {0.0, 0.0, 0.0, 0.0};
1742 
1743  nd_box = sample_boxes[i];
1744  if ( ! nd_box ) continue; /* Skip Null'ed out hard deviants */
1745 
1746  /* Give backend a chance of interrupting us */
1747  vacuum_delay_point();
1748 
1749  /* Find the cells that overlap with this box and put them into the ND_IBOX */
1750  nd_box_overlap(nd_stats, nd_box, &nd_ibox);
1751  memset(at, 0, sizeof(int)*ND_DIMS);
1752 
1753  POSTGIS_DEBUGF(3, " feature %d: ibox (%d, %d, %d, %d) (%d, %d, %d, %d)", i,
1754  nd_ibox.min[0], nd_ibox.min[1], nd_ibox.min[2], nd_ibox.min[3],
1755  nd_ibox.max[0], nd_ibox.max[1], nd_ibox.max[2], nd_ibox.max[3]);
1756 
1757  for ( d = 0; d < nd_stats->ndims; d++ )
1758  {
1759  /* Initialize the starting values */
1760  at[d] = nd_ibox.min[d];
1761  min[d] = nd_stats->extent.min[d];
1762  max[d] = nd_stats->extent.max[d];
1763  cellsize[d] = (max[d] - min[d])/(nd_stats->size[d]);
1764 
1765  /* What's the volume (area) of this feature's box? */
1766  tmp_volume *= (nd_box->max[d] - nd_box->min[d]);
1767  }
1768 
1769  /* Add feature volume (area) to our total */
1770  total_sample_volume = total_sample_volume + tmp_volume;
1771 
1772  /*
1773  * Move through all the overlaped histogram cells values and
1774  * add the box overlap proportion to them.
1775  */
1776  do
1777  {
1778  ND_BOX nd_cell = { {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0} };
1779  double ratio;
1780  /* Create a box for this histogram cell */
1781  for ( d = 0; d < nd_stats->ndims; d++ )
1782  {
1783  nd_cell.min[d] = min[d] + (at[d]+0) * cellsize[d];
1784  nd_cell.max[d] = min[d] + (at[d]+1) * cellsize[d];
1785  }
1786 
1787  /*
1788  * If a feature box is completely inside one cell the ratio will be
1789  * 1.0. If a feature box is 50% in two cells, each cell will get
1790  * 0.5 added on.
1791  */
1792  ratio = nd_box_ratio(&nd_cell, nd_box, nd_stats->ndims);
1793  nd_stats->value[nd_stats_value_index(nd_stats, at)] += ratio;
1794  num_cells += ratio;
1795  POSTGIS_DEBUGF(3, " ratio (%.8g) num_cells (%.8g)", ratio, num_cells);
1796  POSTGIS_DEBUGF(3, " at (%d, %d, %d, %d)", at[0], at[1], at[2], at[3]);
1797  }
1798  while ( nd_increment(&nd_ibox, nd_stats->ndims, at) );
1799 
1800  /* Keep track of overall number of overlaps counted */
1801  total_cell_count += num_cells;
1802  /* How many features have we added to this histogram? */
1803  histogram_features++;
1804  }
1805 
1806  POSTGIS_DEBUGF(3, " histogram_features: %d", histogram_features);
1807  POSTGIS_DEBUGF(3, " sample_rows: %d", sample_rows);
1808  POSTGIS_DEBUGF(3, " table_rows: %.6g", total_rows);
1809 
1810  /* Error out if we got no sample information */
1811  if ( ! histogram_features )
1812  {
1813  POSTGIS_DEBUG(3, " no stats have been gathered");
1814  elog(NOTICE, " no features lie in the stats histogram, invalid stats");
1815  stats->stats_valid = false;
1816  return;
1817  }
1818 
1819  nd_stats->histogram_features = histogram_features;
1820  nd_stats->histogram_cells = histo_cells;
1821  nd_stats->cells_covered = total_cell_count;
1822 
1823  /* Put this histogram data into the right slot/kind */
1824  if ( mode == 2 )
1825  {
1826  stats_slot = STATISTIC_SLOT_2D;
1827  stats_kind = STATISTIC_KIND_2D;
1828  }
1829  else
1830  {
1831  stats_slot = STATISTIC_SLOT_ND;
1832  stats_kind = STATISTIC_KIND_ND;
1833  }
1834 
1835  /* Write the statistics data */
1836  stats->stakind[stats_slot] = stats_kind;
1837  stats->staop[stats_slot] = InvalidOid;
1838  stats->stanumbers[stats_slot] = (float4*)nd_stats;
1839  stats->numnumbers[stats_slot] = nd_stats_size/sizeof(float4);
1840  stats->stanullfrac = (float4)null_cnt/sample_rows;
1841  stats->stawidth = total_width/notnull_cnt;
1842  stats->stadistinct = -1.0;
1843  stats->stats_valid = true;
1844 
1845  POSTGIS_DEBUGF(3, " out: slot 0: kind %d (STATISTIC_KIND_ND)", stats->stakind[0]);
1846  POSTGIS_DEBUGF(3, " out: slot 0: op %d (InvalidOid)", stats->staop[0]);
1847  POSTGIS_DEBUGF(3, " out: slot 0: numnumbers %d", stats->numnumbers[0]);
1848  POSTGIS_DEBUGF(3, " out: null fraction: %f=%d/%d", stats->stanullfrac, null_cnt, sample_rows);
1849  POSTGIS_DEBUGF(3, " out: average width: %d bytes", stats->stawidth);
1850  POSTGIS_DEBUG (3, " out: distinct values: all (no check done)");
1851  POSTGIS_DEBUGF(3, " out: %s", nd_stats_to_json(nd_stats));
1852  /*
1853  POSTGIS_DEBUGF(3, " out histogram:\n%s", nd_stats_to_grid(nd_stats));
1854  */
1855 
1856  return;
1857 }
int gbox_is_valid(const GBOX *gbox)
Return false if any of the dimensions is NaN or infinite.
Definition: gbox.c:197
struct ND_STATS_T ND_STATS
N-dimensional statistics structure.
static char * nd_stats_to_json(const ND_STATS *nd_stats)
Convert an ND_STATS to a JSON representation for external use.
static int nd_box_intersects(const ND_BOX *a, const ND_BOX *b, int ndims)
Return true if ND_BOX a overlaps b, false otherwise.
static int nd_box_init_bounds(ND_BOX *a)
Prepare an ND_BOX for bounds calculation: set the maxes to the smallest thing possible and the mins t...
static int nd_increment(ND_IBOX *ibox, int ndims, int *counter)
Given an n-d index array (counter), and a domain to increment it in (ibox) increment it by one,...
#define STATISTIC_SLOT_ND
static int gbox_ndims(const GBOX *gbox)
Given that geodetic boxes are X/Y/Z regardless of the underlying geometry dimensionality and other bo...
#define ND_DIMS
The maximum number of dimensions our code can handle.
#define STATISTIC_KIND_2D
static int nd_box_merge(const ND_BOX *source, ND_BOX *target)
Create a printable view of the ND_STATS histogram.
#define STATISTIC_KIND_ND
static double total_double(const double *vals, int nvals)
Given double array, return sum of values.
#define SDFACTOR
static void nd_box_from_gbox(const GBOX *gbox, ND_BOX *nd_box)
Set the values of an ND_BOX from a GBOX.
static int nd_box_init(ND_BOX *a)
Zero out an ND_BOX.
static int nd_box_expand(ND_BOX *nd_box, double expansion_factor)
Expand an ND_BOX ever so slightly.
static int nd_box_overlap(const ND_STATS *nd_stats, const ND_BOX *nd_box, ND_IBOX *nd_ibox)
What stats cells overlap with this ND_BOX? Put the lowest cell addresses in ND_IBOX->min and the high...
static double nd_box_ratio(const ND_BOX *b1, const ND_BOX *b2, int ndims)
Returns the proportion of b2 that is covered by b1.
static int nd_stats_value_index(const ND_STATS *stats, int *indexes)
Given a position in the n-d histogram (i,j,k) return the position in the 1-d values array.
static char * nd_box_to_json(const ND_BOX *nd_box, int ndims)
Convert an ND_BOX to a JSON string for printing.
#define STATISTIC_SLOT_2D
static int nd_box_array_distribution(const ND_BOX **nd_boxes, int num_boxes, const ND_BOX *extent, int ndims, double *distribution)
Calculate how much a set of boxes is homogenously distributed or contentrated within one dimension,...
int gserialized_datum_get_gbox_p(Datum gsdatum, GBOX *gbox)
Given a GSERIALIZED datum, as quickly as possible (peaking into the top of the memory) return the gbo...
#define LW_FAILURE
Definition: liblwgeom.h:110
double zmax
Definition: liblwgeom.h:373
double zmin
Definition: liblwgeom.h:372
double mmax
Definition: liblwgeom.h:375
double mmin
Definition: liblwgeom.h:374
float4 max[ND_DIMS]
float4 min[ND_DIMS]
N-dimensional box type for calculations, to avoid doing explicit axis conversions from GBOX in all ca...
int max[ND_DIMS]
int min[ND_DIMS]
N-dimensional box index type.
float4 size[ND_DIMS]
N-dimensional statistics structure.

References ND_STATS_T::cells_covered, ND_STATS_T::extent, gbox_is_valid(), gbox_ndims(), gserialized_datum_get_gbox_p(), ND_STATS_T::histogram_cells, ND_STATS_T::histogram_features, LW_FAILURE, ND_BOX_T::max, ND_IBOX_T::max, ND_BOX_T::min, ND_IBOX_T::min, GBOX::mmax, GBOX::mmin, nd_box_array_distribution(), nd_box_expand(), nd_box_from_gbox(), nd_box_init(), nd_box_init_bounds(), nd_box_intersects(), nd_box_merge(), nd_box_overlap(), nd_box_ratio(), nd_box_to_json(), ND_DIMS, nd_increment(), nd_stats_to_json(), nd_stats_value_index(), ND_STATS_T::ndims, ND_STATS_T::not_null_features, ND_STATS_T::sample_features, SDFACTOR, ND_STATS_T::size, STATISTIC_KIND_2D, STATISTIC_KIND_ND, STATISTIC_SLOT_2D, STATISTIC_SLOT_ND, ND_STATS_T::table_features, total_double(), ND_STATS_T::value, GBOX::zmax, and GBOX::zmin.

Referenced by compute_gserialized_stats().

Here is the call graph for this function:
Here is the caller graph for this function: