From b236795b547815258f7f711b3f3dbbc9efadace3 Mon Sep 17 00:00:00 2001 From: David Zwarg Date: Tue, 7 Feb 2012 18:07:57 +0000 Subject: [PATCH] Corrected clamped values in tests for ST_MapAlgebraExpr and ST_MapAlgebraFct. Implemented prepared statements in ST_MapAlgebraExpr. git-svn-id: http://svn.osgeo.org/postgis/trunk@9068 b70326c6-7e19-0410-871a-916f4a2858ee --- raster/rt_pg/rt_pg.c | 160 +++++++++++++++--- raster/test/regress/rt_mapalgebraexpr.sql | 5 + .../test/regress/rt_mapalgebraexpr_expected | 5 +- raster/test/regress/rt_mapalgebrafct_expected | 4 +- 4 files changed, 142 insertions(+), 32 deletions(-) diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index d01264710..04fb35cce 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -2526,14 +2526,26 @@ Datum RASTER_mapAlgebraExpr(PG_FUNCTION_ARGS) double nodataval = 0.; rt_pixtype newpixeltype; int skipcomputation = 0; - char strnewval[50]; int len = 0; + int argcount = 0; + Oid *argtype = NULL; + const int argkwcount = 3; + char *argkw[] = {"[rast]", "[rast.x]", "[rast.y]"}; + uint8_t argpos[3] = {0}; + char place[5]; + int idx = 0; int ret = -1; TupleDesc tupdesc; SPIPlanPtr spi_plan = NULL; SPITupleTable * tuptable = NULL; HeapTuple tuple; char * strFromText = NULL; + Datum *values = NULL; + Datum datum = (Datum)NULL; + char *nulls = NULL; + bool isnull = FALSE; + int i = 0; + int j = 0; POSTGIS_RT_DEBUG(2, "RASTER_mapAlgebraExpr: Starting..."); @@ -2950,13 +2962,63 @@ Datum RASTER_mapAlgebraExpr(PG_FUNCTION_ARGS) /* Convert [rast.val] to [rast] */ if (initexpr != NULL) { - newexpr = rtpg_strreplace(initexpr, "[rast.val]", "[rast]", NULL); - pfree(initexpr); initexpr=newexpr; + newexpr = rtpg_strreplace(initexpr, "[rast.val]", "[rast]", NULL); + pfree(initexpr); initexpr=newexpr; + + sprintf(place,"$1"); + for (i = 0, j = 1; i < argkwcount; i++) { + len = 0; + newexpr = rtpg_strreplace(initexpr, argkw[i], place, &len); + pfree(initexpr); initexpr=newexpr; + if (len > 0) { + argcount++; + argpos[i] = j++; + + sprintf(place, "$%d", j); + } + else { + argpos[i] = 0; + } + } + + POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraExpr: initexpr = %s", initexpr); + + /* Connect to SPI and prepare the expression */ + ret = SPI_connect(); + if (ret != SPI_OK_CONNECT) { + elog(ERROR, "RASTER_mapAlgebraExpr: Unable to connect to the SPI manager." + " Aborting"); + + if (initexpr) + pfree(initexpr); + rt_raster_destroy(raster); + rt_raster_destroy(newrast); + + PG_RETURN_NULL(); + }; + + /* Type of all arguments is FLOAT8OID */ + argtype = (Oid *) palloc(argcount * sizeof(Oid)); + for (i = 0; i < argcount; i++) argtype[i] = FLOAT8OID; + spi_plan = SPI_prepare(initexpr, argcount, argtype); + + if (spi_plan == NULL) { + elog(ERROR, "RASTER_mapAlgebraExpr: Could not prepare expression." + " Aborting"); + + rt_raster_destroy(raster); + rt_raster_destroy(newrast); + + SPI_finish(); + + pfree(initexpr); + + PG_RETURN_NULL(); + } } for (x = 0; x < width; x++) { for(y = 0; y < height; y++) { - char *tmp; ret = rt_band_get_pixel(band, x, y, &r); /** @@ -2965,35 +3027,68 @@ Datum RASTER_mapAlgebraExpr(PG_FUNCTION_ARGS) **/ if (ret != -1 && FLT_NEQ(r, newnodatavalue)) { if (skipcomputation == 0) { - if (initexpr != NULL) { + /* define values */ + values = (Datum *) palloc(sizeof(Datum) * argcount); + if (values == NULL) { + elog(ERROR, "RASTER_mapAlgebraExpr: Unable to allocate memory for value parameters of prepared statement"); - sprintf(strnewval, "%d", x+1); - newexpr = rtpg_strreplace(initexpr, "[rast.x]", strnewval, NULL); - sprintf(strnewval, "%d", y+1); - tmp = rtpg_strreplace(newexpr, "[rast.y]", strnewval, NULL); - pfree(newexpr); newexpr=tmp; - sprintf(strnewval, "%f", r); - tmp = rtpg_strreplace(newexpr, "[rast]", strnewval, NULL); - pfree(newexpr); newexpr=tmp; + SPI_finish(); + + rt_raster_destroy(raster); + rt_raster_destroy(newrast); + + PG_RETURN_NULL(); + } - POSTGIS_RT_DEBUGF(3, "RASTER_mapAlgebraExpr: (%dx%d), " - "r = %s, newexpr = %s", - x, y, strnewval, newexpr); + /* define nulls */ + nulls = (char *)palloc(argcount); + if (nulls == NULL) { + elog(ERROR, "RASTER_mapAlgebraExpr: Unable to allocate memory for null parameters of prepared statement"); - SPI_connect(); + SPI_finish(); - ret = SPI_execute(newexpr, FALSE, 0); + rt_raster_destroy(raster); + rt_raster_destroy(newrast); + PG_RETURN_NULL(); + } + memset(nulls, 'n', argcount); + + for (i = 0; i < argkwcount; i++) { + idx = argpos[i]; + if (idx < 1) continue; + idx--; + + if (strstr(argkw[i], "[rast.x]") != NULL) { + /* x is 0 based index, but SQL expects 1 based index */ + values[idx] = Float8GetDatum((float)(x+1)); + nulls[idx] = ' '; + } + else if (strstr(argkw[i], "[rast.y]") != NULL) { + /* y is 0 based index, but SQL expects 1 based index */ + values[idx] = Float8GetDatum((float)(y+1)); + nulls[idx] = ' '; + } + else if (strstr(argkw[i], "[rast]") != NULL) { + values[idx] = Float8GetDatum(r); + nulls[idx] = ' '; + } + + } + + ret = SPI_execute_plan(spi_plan, values, nulls, FALSE, 0); + pfree(values); + pfree(nulls); if (ret != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) { elog(ERROR, "RASTER_mapAlgebraExpr: Invalid construction" " for expression. Aborting"); - pfree(newexpr); if (SPI_tuptable) SPI_freetuptable(tuptable); + SPI_freeplan(spi_plan); SPI_finish(); PG_RETURN_NULL(); } @@ -3002,19 +3097,19 @@ Datum RASTER_mapAlgebraExpr(PG_FUNCTION_ARGS) tuptable = SPI_tuptable; tuple = tuptable->vals[0]; - tmp = SPI_getvalue(tuple, tupdesc, 1); - if ( tmp ) { - newval = atof(tmp); - } else { + datum = SPI_getbinval(tuple, tupdesc, 1, &isnull); + if ( SPI_result == SPI_ERROR_NOATTRIBUTE ) { + POSTGIS_RT_DEBUGF(3, "Expression for pixel %d,%d (value %g) errored, skip setting", x+1,y+1,r); + newval = newinitialvalue; + } + else if ( isnull ) { POSTGIS_RT_DEBUGF(3, "Expression for pixel %d,%d (value %g) evaluated to NULL, skip setting", x+1,y+1,r); newval = newinitialvalue; + } else { + newval = DatumGetFloat8(datum); } SPI_freetuptable(tuptable); - - SPI_finish(); - - pfree(newexpr); } else @@ -3031,7 +3126,16 @@ Datum RASTER_mapAlgebraExpr(PG_FUNCTION_ARGS) } } - if (initexpr != NULL) pfree(initexpr); + if (initexpr != NULL) { + SPI_freeplan(spi_plan); + SPI_finish(); + + pfree(initexpr); + } + else { + POSTGIS_RT_DEBUG(3, "RASTER_mapAlgebraExpr: no SPI cleanup"); + } + /* The newrast band has been modified */ diff --git a/raster/test/regress/rt_mapalgebraexpr.sql b/raster/test/regress/rt_mapalgebraexpr.sql index 07449624c..8ab2a6ebf 100644 --- a/raster/test/regress/rt_mapalgebraexpr.sql +++ b/raster/test/regress/rt_mapalgebraexpr.sql @@ -30,6 +30,11 @@ FROM ST_TestRaster(0, 0, 10) rast, generate_series(2, 4) as y ORDER BY x, y; +-- Test divide by zero; blows up the whole query, not just the SPI +SELECT ST_Value(rast, 1, 1), + ST_Value(ST_MapAlgebraExpr(rast, 1, NULL, '[rast]/0'), 1, 1) +FROM ST_TestRaster(0, 0, 10) rast; + -- Test evaluations to null (see #1523) WITH op AS ( select rast AS rin, ST_MapAlgebraExpr(rast, 1, NULL, 'g from (select NULL as g) as foo', 2) diff --git a/raster/test/regress/rt_mapalgebraexpr_expected b/raster/test/regress/rt_mapalgebraexpr_expected index 3478afd0f..7d98be1b1 100644 --- a/raster/test/regress/rt_mapalgebraexpr_expected +++ b/raster/test/regress/rt_mapalgebraexpr_expected @@ -8,9 +8,9 @@ T3||19 T4||2 T5||2 T6||-1 -T7|100| +T7|100|15 T8|100|120 -T9|101| +T9|101|3 T10.6.2|10|40 T10.6.3|10|30 T10.6.4|10|25 @@ -20,5 +20,6 @@ T10.7.4|10|28 T10.8.2|10|50 T10.8.3|10|37 T10.8.4|10|30 +ERROR: division by zero T11.1|10|2 T11.2|10|2 diff --git a/raster/test/regress/rt_mapalgebrafct_expected b/raster/test/regress/rt_mapalgebrafct_expected index d703c0ef8..38f4eaaf4 100644 --- a/raster/test/regress/rt_mapalgebrafct_expected +++ b/raster/test/regress/rt_mapalgebrafct_expected @@ -114,9 +114,9 @@ NOTICE: Pixel value is null. NOTICE: Pixel value is null. | |19 -100| +100|15 100|120 -101| +101|3 213|213 6314|6314 100| -- 2.40.0