PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ RASTER_nMapAlgebraExpr()

Datum RASTER_nMapAlgebraExpr ( PG_FUNCTION_ARGS  )

Definition at line 1289 of file rtpg_mapalgebra.c.

1290 {
1291  MemoryContext mainMemCtx = CurrentMemoryContext;
1292  rtpg_nmapalgebraexpr_arg arg = NULL;
1293  rt_iterator itrset;
1294  uint16_t exprpos[3] = {1, 4, 5};
1295 
1296  int i = 0;
1297  int j = 0;
1298  int k = 0;
1299 
1300  int numraster = 0;
1301  int err = 0;
1302  int allnull = 0;
1303  int allempty = 0;
1304  int noband = 0;
1305  int len = 0;
1306 
1307  TupleDesc tupdesc;
1308  SPITupleTable *tuptable = NULL;
1309  HeapTuple tuple;
1310  Datum datum;
1311  bool isnull = FALSE;
1312 
1313  rt_raster raster = NULL;
1314  rt_band band = NULL;
1315  rt_pgraster *pgraster = NULL;
1316 
1317  const int argkwcount = 12;
1318  char *argkw[] = {
1319  "[rast.x]",
1320  "[rast.y]",
1321  "[rast.val]",
1322  "[rast]",
1323  "[rast1.x]",
1324  "[rast1.y]",
1325  "[rast1.val]",
1326  "[rast1]",
1327  "[rast2.x]",
1328  "[rast2.y]",
1329  "[rast2.val]",
1330  "[rast2]"
1331  };
1332 
1333  if (PG_ARGISNULL(0))
1334  PG_RETURN_NULL();
1335 
1336  /* init argument struct */
1337  arg = rtpg_nmapalgebraexpr_arg_init(argkwcount, argkw);
1338  if (arg == NULL) {
1339  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not initialize argument structure");
1340  PG_RETURN_NULL();
1341  }
1342 
1343  /* let helper function process rastbandarg (0) */
1344  if (!rtpg_nmapalgebra_rastbandarg_process(arg->bandarg, PG_GETARG_ARRAYTYPE_P(0), &allnull, &allempty, &noband)) {
1346  elog(ERROR, "RASTER_nMapAlgebra: Could not process rastbandarg");
1347  PG_RETURN_NULL();
1348  }
1349 
1350  POSTGIS_RT_DEBUGF(4, "allnull, allempty, noband = %d, %d, %d", allnull, allempty, noband);
1351 
1352  /* all rasters are NULL, return NULL */
1353  if (allnull == arg->bandarg->numraster) {
1354  elog(NOTICE, "All input rasters are NULL. Returning NULL");
1356  PG_RETURN_NULL();
1357  }
1358 
1359  /* only work on one or two rasters */
1360  if (arg->bandarg->numraster > 1)
1361  numraster = 2;
1362  else
1363  numraster = 1;
1364 
1365  /* pixel type (2) */
1366  if (!PG_ARGISNULL(2)) {
1367  char *pixtypename = text_to_cstring(PG_GETARG_TEXT_P(2));
1368 
1369  /* Get the pixel type index */
1370  arg->bandarg->pixtype = rt_pixtype_index_from_name(pixtypename);
1371  if (arg->bandarg->pixtype == PT_END) {
1373  elog(ERROR, "RASTER_nMapAlgebraExpr: Invalid pixel type: %s", pixtypename);
1374  PG_RETURN_NULL();
1375  }
1376  }
1377  POSTGIS_RT_DEBUGF(4, "pixeltype: %d", arg->bandarg->pixtype);
1378 
1379  /* extent type (3) */
1380  if (!PG_ARGISNULL(3)) {
1381  char *extenttypename = rtpg_strtoupper(rtpg_trim(text_to_cstring(PG_GETARG_TEXT_P(3))));
1382  arg->bandarg->extenttype = rt_util_extent_type(extenttypename);
1383  }
1384 
1385  if (arg->bandarg->extenttype == ET_CUSTOM) {
1386  if (numraster < 2) {
1387  elog(NOTICE, "CUSTOM extent type not supported. Defaulting to FIRST");
1388  arg->bandarg->extenttype = ET_FIRST;
1389  }
1390  else {
1391  elog(NOTICE, "CUSTOM extent type not supported. Defaulting to INTERSECTION");
1393  }
1394  }
1395  else if (numraster < 2)
1396  arg->bandarg->extenttype = ET_FIRST;
1397 
1398  POSTGIS_RT_DEBUGF(4, "extenttype: %d", arg->bandarg->extenttype);
1399 
1400  /* nodatanodataval (6) */
1401  if (!PG_ARGISNULL(6)) {
1402  arg->callback.nodatanodata.hasval = 1;
1403  arg->callback.nodatanodata.val = PG_GETARG_FLOAT8(6);
1404  }
1405 
1406  err = 0;
1407  /* all rasters are empty, return empty raster */
1408  if (allempty == arg->bandarg->numraster) {
1409  elog(NOTICE, "All input rasters are empty. Returning empty raster");
1410  err = 1;
1411  }
1412  /* all rasters don't have indicated band, return empty raster */
1413  else if (noband == arg->bandarg->numraster) {
1414  elog(NOTICE, "All input rasters do not have bands at indicated indexes. Returning empty raster");
1415  err = 1;
1416  }
1417  if (err) {
1419 
1420  raster = rt_raster_new(0, 0);
1421  if (raster == NULL) {
1422  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not create empty raster");
1423  PG_RETURN_NULL();
1424  }
1425 
1426  pgraster = rt_raster_serialize(raster);
1428  if (!pgraster) PG_RETURN_NULL();
1429 
1430  SET_VARSIZE(pgraster, pgraster->size);
1431  PG_RETURN_POINTER(pgraster);
1432  }
1433 
1434  /* connect SPI */
1435  if (SPI_connect() != SPI_OK_CONNECT) {
1437  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not connect to the SPI manager");
1438  PG_RETURN_NULL();
1439  }
1440 
1441  /*
1442  process expressions
1443 
1444  exprpos elements are:
1445  1 - expression => spi_plan[0]
1446  4 - nodata1expr => spi_plan[1]
1447  5 - nodata2expr => spi_plan[2]
1448  */
1449  for (i = 0; i < arg->callback.exprcount; i++) {
1450  char *expr = NULL;
1451  char *tmp = NULL;
1452  char *sql = NULL;
1453  char place[12] = "$1";
1454 
1455  if (PG_ARGISNULL(exprpos[i]))
1456  continue;
1457 
1458  expr = text_to_cstring(PG_GETARG_TEXT_P(exprpos[i]));
1459  POSTGIS_RT_DEBUGF(3, "raw expr of argument #%d: %s", exprpos[i], expr);
1460 
1461  for (j = 0, k = 1; j < argkwcount; j++) {
1462  /* attempt to replace keyword with placeholder */
1463  len = 0;
1464  tmp = rtpg_strreplace(expr, argkw[j], place, &len);
1465  pfree(expr);
1466  expr = tmp;
1467 
1468  if (len) {
1469  POSTGIS_RT_DEBUGF(4, "kw #%d (%s) at pos $%d", j, argkw[j], k);
1470  arg->callback.expr[i].spi_argcount++;
1471  arg->callback.expr[i].spi_argpos[j] = k++;
1472 
1473  sprintf(place, "$%d", k);
1474  }
1475  else
1476  arg->callback.expr[i].spi_argpos[j] = 0;
1477  }
1478 
1479  len = strlen("SELECT (") + strlen(expr) + strlen(")::double precision");
1480  sql = (char *) palloc(len + 1);
1481  if (sql == NULL) {
1483  SPI_finish();
1484  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not allocate memory for expression parameter %d", exprpos[i]);
1485  PG_RETURN_NULL();
1486  }
1487 
1488  memcpy(sql, "SELECT (", strlen("SELECT ("));
1489  memcpy(sql + strlen("SELECT ("), expr, strlen(expr));
1490  memcpy(sql + strlen("SELECT (") + strlen(expr), ")::double precision", strlen(")::double precision"));
1491  sql[len] = '\0';
1492 
1493  POSTGIS_RT_DEBUGF(3, "sql #%d: %s", exprpos[i], sql);
1494 
1495  /* prepared plan */
1496  if (arg->callback.expr[i].spi_argcount) {
1497  Oid *argtype = (Oid *) palloc(arg->callback.expr[i].spi_argcount * sizeof(Oid));
1498  POSTGIS_RT_DEBUGF(3, "expression parameter %d is a prepared plan", exprpos[i]);
1499  if (argtype == NULL) {
1500  pfree(sql);
1502  SPI_finish();
1503  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not allocate memory for prepared plan argtypes of expression parameter %d", exprpos[i]);
1504  PG_RETURN_NULL();
1505  }
1506 
1507  /* specify datatypes of parameters */
1508  for (j = 0, k = 0; j < argkwcount; j++) {
1509  if (arg->callback.expr[i].spi_argpos[j] < 1) continue;
1510 
1511  /* positions are INT4 */
1512  if (
1513  (strstr(argkw[j], "[rast.x]") != NULL) ||
1514  (strstr(argkw[j], "[rast.y]") != NULL) ||
1515  (strstr(argkw[j], "[rast1.x]") != NULL) ||
1516  (strstr(argkw[j], "[rast1.y]") != NULL) ||
1517  (strstr(argkw[j], "[rast2.x]") != NULL) ||
1518  (strstr(argkw[j], "[rast2.y]") != NULL)
1519  )
1520  argtype[k] = INT4OID;
1521  /* everything else is FLOAT8 */
1522  else
1523  argtype[k] = FLOAT8OID;
1524 
1525  k++;
1526  }
1527 
1528  arg->callback.expr[i].spi_plan = SPI_prepare(sql, arg->callback.expr[i].spi_argcount, argtype);
1529  pfree(argtype);
1530  pfree(sql);
1531 
1532  if (arg->callback.expr[i].spi_plan == NULL) {
1534  SPI_finish();
1535  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not create prepared plan of expression parameter %d", exprpos[i]);
1536  PG_RETURN_NULL();
1537  }
1538  }
1539  /* no args, just execute query */
1540  else {
1541  POSTGIS_RT_DEBUGF(3, "expression parameter %d has no args, simply executing", exprpos[i]);
1542  err = SPI_execute(sql, TRUE, 0);
1543  pfree(sql);
1544 
1545  if (err != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
1547  SPI_finish();
1548  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not evaluate expression parameter %d", exprpos[i]);
1549  PG_RETURN_NULL();
1550  }
1551 
1552  /* get output of prepared plan */
1553  tupdesc = SPI_tuptable->tupdesc;
1554  tuptable = SPI_tuptable;
1555  tuple = tuptable->vals[0];
1556 
1557  datum = SPI_getbinval(tuple, tupdesc, 1, &isnull);
1558  if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
1559  if (SPI_tuptable) SPI_freetuptable(tuptable);
1561  SPI_finish();
1562  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not get result of expression parameter %d", exprpos[i]);
1563  PG_RETURN_NULL();
1564  }
1565 
1566  if (!isnull) {
1567  arg->callback.expr[i].hasval = 1;
1568  arg->callback.expr[i].val = DatumGetFloat8(datum);
1569  }
1570 
1571  if (SPI_tuptable) SPI_freetuptable(tuptable);
1572  }
1573  }
1574 
1575  /* determine nodataval and possibly pixtype */
1576  /* band to check */
1577  switch (arg->bandarg->extenttype) {
1578  case ET_LAST:
1579  case ET_SECOND:
1580  if (numraster > 1)
1581  i = 1;
1582  else
1583  i = 0;
1584  break;
1585  default:
1586  i = 0;
1587  break;
1588  }
1589  /* find first viable band */
1590  if (!arg->bandarg->hasband[i]) {
1591  for (i = 0; i < numraster; i++) {
1592  if (arg->bandarg->hasband[i])
1593  break;
1594  }
1595  if (i >= numraster)
1596  i = numraster - 1;
1597  }
1598  band = rt_raster_get_band(arg->bandarg->raster[i], arg->bandarg->nband[i]);
1599 
1600  /* set pixel type if PT_END */
1601  if (arg->bandarg->pixtype == PT_END)
1603 
1604  /* set hasnodata and nodataval */
1605  arg->bandarg->hasnodata = 1;
1608  else
1610 
1611  POSTGIS_RT_DEBUGF(4, "pixtype, hasnodata, nodataval: %s, %d, %f", rt_pixtype_name(arg->bandarg->pixtype), arg->bandarg->hasnodata, arg->bandarg->nodataval);
1612 
1613  /* init itrset */
1614  itrset = palloc(sizeof(struct rt_iterator_t) * numraster);
1615  if (itrset == NULL) {
1617  SPI_finish();
1618  elog(ERROR, "RASTER_nMapAlgebra: Could not allocate memory for iterator arguments");
1619  PG_RETURN_NULL();
1620  }
1621 
1622  /* set itrset */
1623  for (i = 0; i < numraster; i++) {
1624  itrset[i].raster = arg->bandarg->raster[i];
1625  itrset[i].nband = arg->bandarg->nband[i];
1626  itrset[i].nbnodata = 1;
1627  }
1628 
1629  /* pass everything to iterator */
1630  err = rt_raster_iterator(
1631  itrset, numraster,
1632  arg->bandarg->extenttype, arg->bandarg->cextent,
1633  arg->bandarg->pixtype,
1634  arg->bandarg->hasnodata, arg->bandarg->nodataval,
1635  0, 0,
1636  NULL,
1637  &(arg->callback),
1639  &raster
1640  );
1641 
1642  pfree(itrset);
1644 
1645  if (err != ES_NONE) {
1646  SPI_finish();
1647  elog(ERROR, "RASTER_nMapAlgebraExpr: Could not run raster iterator function");
1648  PG_RETURN_NULL();
1649  }
1650  else if (raster == NULL) {
1651  SPI_finish();
1652  PG_RETURN_NULL();
1653  }
1654 
1655  /* switch to prior memory context to ensure memory allocated in correct context */
1656  MemoryContextSwitchTo(mainMemCtx);
1657 
1658  pgraster = rt_raster_serialize(raster);
1660 
1661  /* finish SPI */
1662  SPI_finish();
1663 
1664  if (!pgraster)
1665  PG_RETURN_NULL();
1666 
1667  SET_VARSIZE(pgraster, pgraster->size);
1668  PG_RETURN_POINTER(pgraster);
1669 }
#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:197
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:69
rt_raster raster
Definition: librtcore.h:2596
uint16_t nband
Definition: librtcore.h:2597
uint8_t nbnodata
Definition: librtcore.h:2598
Struct definitions.
Definition: librtcore.h:2403
rtpg_nmapalgebraexpr_callback_arg callback
rtpg_nmapalgebra_arg bandarg
struct rtpg_nmapalgebraexpr_callback_arg::@24 expr[3]
struct rtpg_nmapalgebraexpr_callback_arg::@25 nodatanodata

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: