PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ RASTER_nMapAlgebraExpr()

Datum RASTER_nMapAlgebraExpr ( PG_FUNCTION_ARGS  )

Definition at line 1335 of file rtpg_mapalgebra.c.

1336 {
1337  MemoryContext mainMemCtx = CurrentMemoryContext;
1338  rtpg_nmapalgebraexpr_arg arg = NULL;
1339  rt_iterator itrset;
1340  uint16_t exprpos[3] = {1, 4, 5};
1341 
1342  int i = 0;
1343  int j = 0;
1344  int k = 0;
1345 
1346  int numraster = 0;
1347  int err = 0;
1348  int allnull = 0;
1349  int allempty = 0;
1350  int noband = 0;
1351  int len = 0;
1352 
1353  TupleDesc tupdesc;
1354  SPITupleTable *tuptable = NULL;
1355  HeapTuple tuple;
1356  Datum datum;
1357  bool isnull = FALSE;
1358 
1359  rt_raster raster = NULL;
1360  rt_band band = NULL;
1361  rt_pgraster *pgraster = NULL;
1362 
1363  const int argkwcount = 12;
1364  char *argkw[] = {
1365  "[rast.x]",
1366  "[rast.y]",
1367  "[rast.val]",
1368  "[rast]",
1369  "[rast1.x]",
1370  "[rast1.y]",
1371  "[rast1.val]",
1372  "[rast1]",
1373  "[rast2.x]",
1374  "[rast2.y]",
1375  "[rast2.val]",
1376  "[rast2]"
1377  };
1378 
1379  if (PG_ARGISNULL(0))
1380  PG_RETURN_NULL();
1381 
1382  /* init argument struct */
1383  arg = rtpg_nmapalgebraexpr_arg_init(argkwcount, argkw);
1384  if (arg == NULL) {
1385  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not initialize argument structure");
1386  PG_RETURN_NULL();
1387  }
1388 
1389  /* let helper function process rastbandarg (0) */
1390  if (!rtpg_nmapalgebra_rastbandarg_process(arg->bandarg, PG_GETARG_ARRAYTYPE_P(0), &allnull, &allempty, &noband)) {
1392  elog(ERROR, "RASTER_nMapAlgebra: Could not process rastbandarg");
1393  PG_RETURN_NULL();
1394  }
1395 
1396  POSTGIS_RT_DEBUGF(4, "allnull, allempty, noband = %d, %d, %d", allnull, allempty, noband);
1397 
1398  /* all rasters are NULL, return NULL */
1399  if (allnull == arg->bandarg->numraster) {
1400  elog(NOTICE, "All input rasters are NULL. Returning NULL");
1402  PG_RETURN_NULL();
1403  }
1404 
1405  /* only work on one or two rasters */
1406  if (arg->bandarg->numraster > 1)
1407  numraster = 2;
1408  else
1409  numraster = 1;
1410 
1411  /* pixel type (2) */
1412  if (!PG_ARGISNULL(2)) {
1413  char *pixtypename = text_to_cstring(PG_GETARG_TEXT_P(2));
1414 
1415  /* Get the pixel type index */
1416  arg->bandarg->pixtype = rt_pixtype_index_from_name(pixtypename);
1417  if (arg->bandarg->pixtype == PT_END) {
1419  elog(ERROR, "RASTER_nMapAlgebraExpr: Invalid pixel type: %s", pixtypename);
1420  PG_RETURN_NULL();
1421  }
1422  }
1423  POSTGIS_RT_DEBUGF(4, "pixeltype: %d", arg->bandarg->pixtype);
1424 
1425  /* extent type (3) */
1426  if (!PG_ARGISNULL(3)) {
1427  char *extenttypename = rtpg_strtoupper(rtpg_trim(text_to_cstring(PG_GETARG_TEXT_P(3))));
1428  arg->bandarg->extenttype = rt_util_extent_type(extenttypename);
1429  }
1430 
1431  if (arg->bandarg->extenttype == ET_CUSTOM) {
1432  if (numraster < 2) {
1433  elog(NOTICE, "CUSTOM extent type not supported. Defaulting to FIRST");
1434  arg->bandarg->extenttype = ET_FIRST;
1435  }
1436  else {
1437  elog(NOTICE, "CUSTOM extent type not supported. Defaulting to INTERSECTION");
1439  }
1440  }
1441  else if (numraster < 2)
1442  arg->bandarg->extenttype = ET_FIRST;
1443 
1444  POSTGIS_RT_DEBUGF(4, "extenttype: %d", arg->bandarg->extenttype);
1445 
1446  /* nodatanodataval (6) */
1447  if (!PG_ARGISNULL(6)) {
1448  arg->callback.nodatanodata.hasval = 1;
1449  arg->callback.nodatanodata.val = PG_GETARG_FLOAT8(6);
1450  }
1451 
1452  err = 0;
1453  /* all rasters are empty, return empty raster */
1454  if (allempty == arg->bandarg->numraster) {
1455  elog(NOTICE, "All input rasters are empty. Returning empty raster");
1456  err = 1;
1457  }
1458  /* all rasters don't have indicated band, return empty raster */
1459  else if (noband == arg->bandarg->numraster) {
1460  elog(NOTICE, "All input rasters do not have bands at indicated indexes. Returning empty raster");
1461  err = 1;
1462  }
1463  if (err) {
1465 
1466  raster = rt_raster_new(0, 0);
1467  if (raster == NULL) {
1468  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not create empty raster");
1469  PG_RETURN_NULL();
1470  }
1471 
1472  pgraster = rt_raster_serialize(raster);
1474  if (!pgraster) PG_RETURN_NULL();
1475 
1476  SET_VARSIZE(pgraster, pgraster->size);
1477  PG_RETURN_POINTER(pgraster);
1478  }
1479 
1480  /* connect SPI */
1481  if (SPI_connect() != SPI_OK_CONNECT) {
1483  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not connect to the SPI manager");
1484  PG_RETURN_NULL();
1485  }
1486 
1487  /*
1488  process expressions
1489 
1490  exprpos elements are:
1491  1 - expression => spi_plan[0]
1492  4 - nodata1expr => spi_plan[1]
1493  5 - nodata2expr => spi_plan[2]
1494  */
1495  for (i = 0; i < arg->callback.exprcount; i++) {
1496  char *expr = NULL;
1497  char *tmp = NULL;
1498  char *sql = NULL;
1499  char place[12] = "$1";
1500 
1501  if (PG_ARGISNULL(exprpos[i]))
1502  continue;
1503 
1504  expr = text_to_cstring(PG_GETARG_TEXT_P(exprpos[i]));
1505  POSTGIS_RT_DEBUGF(3, "raw expr of argument #%d: %s", exprpos[i], expr);
1506 
1507  for (j = 0, k = 1; j < argkwcount; j++) {
1508  /* attempt to replace keyword with placeholder */
1509  len = 0;
1510  tmp = rtpg_strreplace(expr, argkw[j], place, &len);
1511  pfree(expr);
1512  expr = tmp;
1513 
1514  if (len) {
1515  POSTGIS_RT_DEBUGF(4, "kw #%d (%s) at pos $%d", j, argkw[j], k);
1516  arg->callback.expr[i].spi_argcount++;
1517  arg->callback.expr[i].spi_argpos[j] = k++;
1518 
1519  sprintf(place, "$%d", k);
1520  }
1521  else
1522  arg->callback.expr[i].spi_argpos[j] = 0;
1523  }
1524 
1525  len = strlen("SELECT (") + strlen(expr) + strlen(")::double precision");
1526  sql = (char *) palloc(len + 1);
1527  if (sql == NULL) {
1529  SPI_finish();
1530  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not allocate memory for expression parameter %d", exprpos[i]);
1531  PG_RETURN_NULL();
1532  }
1533 
1534  memcpy(sql, "SELECT (", strlen("SELECT ("));
1535  memcpy(sql + strlen("SELECT ("), expr, strlen(expr));
1536  memcpy(sql + strlen("SELECT (") + strlen(expr), ")::double precision", strlen(")::double precision"));
1537  sql[len] = '\0';
1538 
1539  POSTGIS_RT_DEBUGF(3, "sql #%d: %s", exprpos[i], sql);
1540 
1541  /* prepared plan */
1542  if (arg->callback.expr[i].spi_argcount) {
1543  Oid *argtype = (Oid *) palloc(arg->callback.expr[i].spi_argcount * sizeof(Oid));
1544  POSTGIS_RT_DEBUGF(3, "expression parameter %d is a prepared plan", exprpos[i]);
1545  if (argtype == NULL) {
1546  pfree(sql);
1548  SPI_finish();
1549  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not allocate memory for prepared plan argtypes of expression parameter %d", exprpos[i]);
1550  PG_RETURN_NULL();
1551  }
1552 
1553  /* specify datatypes of parameters */
1554  for (j = 0, k = 0; j < argkwcount; j++) {
1555  if (arg->callback.expr[i].spi_argpos[j] < 1) continue;
1556 
1557  /* positions are INT4 */
1558  if (
1559  (strstr(argkw[j], "[rast.x]") != NULL) ||
1560  (strstr(argkw[j], "[rast.y]") != NULL) ||
1561  (strstr(argkw[j], "[rast1.x]") != NULL) ||
1562  (strstr(argkw[j], "[rast1.y]") != NULL) ||
1563  (strstr(argkw[j], "[rast2.x]") != NULL) ||
1564  (strstr(argkw[j], "[rast2.y]") != NULL)
1565  )
1566  argtype[k] = INT4OID;
1567  /* everything else is FLOAT8 */
1568  else
1569  argtype[k] = FLOAT8OID;
1570 
1571  k++;
1572  }
1573 
1574  arg->callback.expr[i].spi_plan = SPI_prepare(sql, arg->callback.expr[i].spi_argcount, argtype);
1575  pfree(argtype);
1576  pfree(sql);
1577 
1578  if (arg->callback.expr[i].spi_plan == NULL) {
1580  SPI_finish();
1581  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not create prepared plan of expression parameter %d", exprpos[i]);
1582  PG_RETURN_NULL();
1583  }
1584  }
1585  /* no args, just execute query */
1586  else {
1587  POSTGIS_RT_DEBUGF(3, "expression parameter %d has no args, simply executing", exprpos[i]);
1588  err = SPI_execute(sql, TRUE, 0);
1589  pfree(sql);
1590 
1591  if (err != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
1593  SPI_finish();
1594  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not evaluate expression parameter %d", exprpos[i]);
1595  PG_RETURN_NULL();
1596  }
1597 
1598  /* get output of prepared plan */
1599  tupdesc = SPI_tuptable->tupdesc;
1600  tuptable = SPI_tuptable;
1601  tuple = tuptable->vals[0];
1602 
1603  datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
1604  if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
1605  if (SPI_tuptable) SPI_freetuptable(tuptable);
1607  SPI_finish();
1608  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not get result of expression parameter %d", exprpos[i]);
1609  PG_RETURN_NULL();
1610  }
1611 
1612  if (!isnull) {
1613  arg->callback.expr[i].hasval = 1;
1614  arg->callback.expr[i].val = DatumGetFloat8(datum);
1615  }
1616 
1617  if (SPI_tuptable) SPI_freetuptable(tuptable);
1618  }
1619  }
1620 
1621  /* determine nodataval and possibly pixtype */
1622  /* band to check */
1623  switch (arg->bandarg->extenttype) {
1624  case ET_LAST:
1625  case ET_SECOND:
1626  if (numraster > 1)
1627  i = 1;
1628  else
1629  i = 0;
1630  break;
1631  default:
1632  i = 0;
1633  break;
1634  }
1635  /* find first viable band */
1636  if (!arg->bandarg->hasband[i]) {
1637  for (i = 0; i < numraster; i++) {
1638  if (arg->bandarg->hasband[i])
1639  break;
1640  }
1641  if (i >= numraster)
1642  i = numraster - 1;
1643  }
1644  band = rt_raster_get_band(arg->bandarg->raster[i], arg->bandarg->nband[i]);
1645 
1646  /* set pixel type if PT_END */
1647  if (arg->bandarg->pixtype == PT_END)
1649 
1650  /* set hasnodata and nodataval */
1651  arg->bandarg->hasnodata = 1;
1654  else
1656 
1657  POSTGIS_RT_DEBUGF(4, "pixtype, hasnodata, nodataval: %s, %d, %f", rt_pixtype_name(arg->bandarg->pixtype), arg->bandarg->hasnodata, arg->bandarg->nodataval);
1658 
1659  /* init itrset */
1660  itrset = palloc(sizeof(struct rt_iterator_t) * numraster);
1661  if (itrset == NULL) {
1663  SPI_finish();
1664  elog(ERROR, "RASTER_nMapAlgebra: Could not allocate memory for iterator arguments");
1665  PG_RETURN_NULL();
1666  }
1667 
1668  /* set itrset */
1669  for (i = 0; i < numraster; i++) {
1670  itrset[i].raster = arg->bandarg->raster[i];
1671  itrset[i].nband = arg->bandarg->nband[i];
1672  itrset[i].nbnodata = 1;
1673  }
1674 
1675  /* pass everything to iterator */
1676  err = rt_raster_iterator(
1677  itrset, numraster,
1678  arg->bandarg->extenttype, arg->bandarg->cextent,
1679  arg->bandarg->pixtype,
1680  arg->bandarg->hasnodata, arg->bandarg->nodataval,
1681  0, 0,
1682  NULL,
1683  &(arg->callback),
1685  &raster
1686  );
1687 
1688  pfree(itrset);
1690 
1691  if (err != ES_NONE) {
1692  SPI_finish();
1693  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not run raster iterator function");
1694  PG_RETURN_NULL();
1695  }
1696  else if (raster == NULL) {
1697  SPI_finish();
1698  PG_RETURN_NULL();
1699  }
1700 
1701  /* switch to prior memory context to ensure memory allocated in correct context */
1702  MemoryContextSwitchTo(mainMemCtx);
1703 
1704  pgraster = rt_raster_serialize(raster);
1706 
1707  /* finish SPI */
1708  SPI_finish();
1709 
1710  if (!pgraster)
1711  PG_RETURN_NULL();
1712 
1713  SET_VARSIZE(pgraster, pgraster->size);
1714  PG_RETURN_POINTER(pgraster);
1715 }
#define TRUE
Definition: dbfopen.c:73
#define FALSE
Definition: dbfopen.c:72
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition: rt_band.c:674
rt_pixtype rt_pixtype_index_from_name(const char *pixname)
Definition: rt_pixel.c:80
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:86
@ PT_END
Definition: librtcore.h:199
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition: rt_raster.c:52
rt_extenttype rt_util_extent_type(const char *name)
Definition: rt_util.c:194
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
Definition: rt_band.c:1902
@ ES_NONE
Definition: librtcore.h:182
rt_errorstate rt_raster_iterator(rt_iterator itrset, uint16_t itrcount, rt_extenttype extenttype, rt_raster customextent, rt_pixtype pixtype, uint8_t hasnodata, double nodataval, uint16_t distancex, uint16_t distancey, rt_mask mask, void *userarg, int(*callback)(rt_iterator_arg arg, void *userarg, double *value, int *nodata), rt_raster *rtnraster)
n-raster iterator.
@ ET_CUSTOM
Definition: librtcore.h:208
@ ET_LAST
Definition: librtcore.h:207
@ ET_INTERSECTION
Definition: librtcore.h:203
@ ET_SECOND
Definition: librtcore.h:206
@ ET_FIRST
Definition: librtcore.h:205
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition: rt_band.c:1887
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition: rt_band.c:631
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition: rt_pixel.c:110
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:385
band
Definition: ovdump.py:58
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
char * rtpg_strtoupper(char *str)
char * rtpg_trim(const char *input)
char * rtpg_strreplace(const char *str, const char *oldstr, const char *newstr, int *count)
Definition: rtpg_internal.c:55
static void rtpg_nmapalgebraexpr_arg_destroy(rtpg_nmapalgebraexpr_arg arg)
static rtpg_nmapalgebraexpr_arg rtpg_nmapalgebraexpr_arg_init(int cnt, char **kw)
static int rtpg_nmapalgebra_rastbandarg_process(rtpg_nmapalgebra_arg arg, ArrayType *array, int *allnull, int *allempty, int *noband)
static int rtpg_nmapalgebraexpr_callback(rt_iterator_arg arg, void *userarg, double *value, int *nodata)
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:73
rt_raster raster
Definition: librtcore.h:2589
uint16_t nband
Definition: librtcore.h:2590
uint8_t nbnodata
Definition: librtcore.h:2591
Struct definitions.
Definition: librtcore.h:2396
rtpg_nmapalgebraexpr_callback_arg callback
rtpg_nmapalgebra_arg bandarg
struct rtpg_nmapalgebraexpr_callback_arg::@23 nodatanodata
struct rtpg_nmapalgebraexpr_callback_arg::@22 expr[3]

References ovdump::band, rtpg_nmapalgebraexpr_arg_t::bandarg, rtpg_nmapalgebraexpr_arg_t::callback, rtpg_nmapalgebra_arg_t::cextent, ES_NONE, ET_CUSTOM, ET_FIRST, ET_INTERSECTION, ET_LAST, ET_SECOND, rtpg_nmapalgebraexpr_callback_arg::expr, rtpg_nmapalgebraexpr_callback_arg::exprcount, rtpg_nmapalgebra_arg_t::extenttype, FALSE, rtpg_nmapalgebra_arg_t::hasband, rtpg_nmapalgebra_arg_t::hasnodata, rtpg_nmapalgebraexpr_callback_arg::hasval, rt_iterator_t::nband, rtpg_nmapalgebra_arg_t::nband, rt_iterator_t::nbnodata, rtpg_nmapalgebraexpr_callback_arg::nodatanodata, rtpg_nmapalgebra_arg_t::nodataval, rtpg_nmapalgebra_arg_t::numraster, rtpg_nmapalgebra_arg_t::pixtype, POSTGIS_RT_DEBUGF, PT_END, rt_iterator_t::raster, rtpg_nmapalgebra_arg_t::raster, rtrowdump::raster, rt_band_get_hasnodata_flag(), rt_band_get_min_value(), rt_band_get_nodata(), rt_band_get_pixtype(), rt_pixtype_index_from_name(), rt_pixtype_name(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_iterator(), rt_raster_new(), rt_raster_serialize(), rt_util_extent_type(), rtpg_nmapalgebra_rastbandarg_process(), rtpg_nmapalgebraexpr_arg_destroy(), rtpg_nmapalgebraexpr_arg_init(), rtpg_nmapalgebraexpr_callback(), rtpg_strreplace(), rtpg_strtoupper(), rtpg_trim(), rt_raster_serialized_t::size, rtpg_nmapalgebraexpr_callback_arg::spi_argcount, rtpg_nmapalgebraexpr_callback_arg::spi_argpos, rtpg_nmapalgebraexpr_callback_arg::spi_plan, rtgdalraster::sql, TRUE, and rtpg_nmapalgebraexpr_callback_arg::val.

Here is the call graph for this function: