33 #include <utils/builtins.h> 34 #include "utils/lsyscache.h" 35 #include "utils/array.h" 36 #include "catalog/pg_type.h" 37 #include <executor/spi.h> 40 #include "../../postgis_config.h" 42 #if POSTGIS_PGSQL_VERSION > 92 43 #include "access/htup_details.h" 76 int32_t bandindex = 1;
77 bool exclude_nodata_value =
TRUE;
83 int values_length = 6;
84 Datum values[values_length];
85 bool nulls[values_length];
92 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
96 PG_FREE_IF_COPY(pgraster, 0);
97 elog(ERROR,
"RASTER_summaryStats: Cannot deserialize raster");
102 if (!PG_ARGISNULL(1))
103 bandindex = PG_GETARG_INT32(1);
105 if (bandindex < 1 || bandindex > num_bands) {
106 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
108 PG_FREE_IF_COPY(pgraster, 0);
113 if (!PG_ARGISNULL(2))
114 exclude_nodata_value = PG_GETARG_BOOL(2);
117 if (!PG_ARGISNULL(3)) {
118 sample = PG_GETARG_FLOAT8(3);
119 if (sample < 0 || sample > 1) {
120 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
122 PG_FREE_IF_COPY(pgraster, 0);
125 else if (
FLT_EQ(sample, 0.0))
134 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
136 PG_FREE_IF_COPY(pgraster, 0);
144 PG_FREE_IF_COPY(pgraster, 0);
146 elog(NOTICE,
"Cannot compute summary statistics for band at index %d. Returning NULL", bandindex);
151 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
153 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
155 "function returning record called in context " 156 "that cannot accept type record" 161 BlessTupleDesc(tupdesc);
163 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
165 values[0] = Int64GetDatum(stats->
count);
166 if (stats->
count > 0) {
167 values[1] = Float8GetDatum(stats->
sum);
168 values[2] = Float8GetDatum(stats->
mean);
169 values[3] = Float8GetDatum(stats->
stddev);
170 values[4] = Float8GetDatum(stats->
min);
171 values[5] = Float8GetDatum(stats->
max);
182 tuple = heap_form_tuple(tupdesc, values, nulls);
185 result = HeapTupleGetDatum(tuple);
190 PG_RETURN_DATUM(result);
199 text *tablenametext = NULL;
200 char *tablename = NULL;
201 text *colnametext = NULL;
202 char *colname = NULL;
203 int32_t bandindex = 1;
204 bool exclude_nodata_value =
TRUE;
212 SPITupleTable *tuptable = NULL;
227 int values_length = 6;
228 Datum values[values_length];
229 bool nulls[values_length];
233 if (PG_ARGISNULL(0)) {
234 elog(NOTICE,
"Table name must be provided");
237 tablenametext = PG_GETARG_TEXT_P(0);
238 tablename = text_to_cstring(tablenametext);
239 if (!strlen(tablename)) {
240 elog(NOTICE,
"Table name must be provided");
245 if (PG_ARGISNULL(1)) {
246 elog(NOTICE,
"Column name must be provided");
249 colnametext = PG_GETARG_TEXT_P(1);
250 colname = text_to_cstring(colnametext);
251 if (!strlen(colname)) {
252 elog(NOTICE,
"Column name must be provided");
257 if (!PG_ARGISNULL(2))
258 bandindex = PG_GETARG_INT32(2);
261 if (!PG_ARGISNULL(3))
262 exclude_nodata_value = PG_GETARG_BOOL(3);
265 if (!PG_ARGISNULL(4)) {
266 sample = PG_GETARG_FLOAT8(4);
267 if (sample < 0 || sample > 1) {
268 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
272 else if (
FLT_EQ(sample, 0.0))
280 spi_result = SPI_connect();
281 if (spi_result != SPI_OK_CONNECT) {
283 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot connect to database using SPI");
288 len =
sizeof(char) * (strlen(
"SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
289 sql = (
char *) palloc(len);
291 if (SPI_tuptable) SPI_freetuptable(tuptable);
293 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot allocate memory for sql");
298 snprintf(sql, len,
"SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
299 portal = SPI_cursor_open_with_args(
309 SPI_cursor_fetch(portal,
TRUE, 1);
310 while (SPI_processed == 1 && SPI_tuptable != NULL) {
311 tupdesc = SPI_tuptable->tupdesc;
312 tuptable = SPI_tuptable;
313 tuple = tuptable->vals[0];
315 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
316 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
318 if (SPI_tuptable) SPI_freetuptable(tuptable);
319 SPI_cursor_close(portal);
322 if (NULL != rtn) pfree(rtn);
323 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot get raster of coverage");
327 SPI_cursor_fetch(portal,
TRUE, 1);
331 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
336 if (SPI_tuptable) SPI_freetuptable(tuptable);
337 SPI_cursor_close(portal);
340 if (NULL != rtn) pfree(rtn);
341 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot deserialize raster");
347 if (bandindex < 1 || bandindex > num_bands) {
348 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
352 if (SPI_tuptable) SPI_freetuptable(tuptable);
353 SPI_cursor_close(portal);
356 if (NULL != rtn) pfree(rtn);
363 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
367 if (SPI_tuptable) SPI_freetuptable(tuptable);
368 SPI_cursor_close(portal);
371 if (NULL != rtn) pfree(rtn);
382 elog(NOTICE,
"Cannot compute summary statistics for band at index %d. Returning NULL", bandindex);
384 if (SPI_tuptable) SPI_freetuptable(tuptable);
385 SPI_cursor_close(portal);
388 if (NULL != rtn) pfree(rtn);
393 if (stats->
count > 0) {
398 if (SPI_tuptable) SPI_freetuptable(tuptable);
399 SPI_cursor_close(portal);
402 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot allocate memory for summary stats of coverage");
421 if (stats->
min < rtn->
min)
423 if (stats->
max > rtn->
max)
431 SPI_cursor_fetch(portal,
TRUE, 1);
434 if (SPI_tuptable) SPI_freetuptable(tuptable);
435 SPI_cursor_close(portal);
439 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot compute coverage summary stats");
453 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
455 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
457 "function returning record called in context " 458 "that cannot accept type record" 463 BlessTupleDesc(tupdesc);
465 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
467 values[0] = Int64GetDatum(rtn->
count);
468 if (rtn->
count > 0) {
469 values[1] = Float8GetDatum(rtn->
sum);
470 values[2] = Float8GetDatum(rtn->
mean);
471 values[3] = Float8GetDatum(rtn->
stddev);
472 values[4] = Float8GetDatum(rtn->
min);
473 values[5] = Float8GetDatum(rtn->
max);
484 tuple = heap_form_tuple(tupdesc, values, nulls);
487 result = HeapTupleGetDatum(tuple);
492 PG_RETURN_DATUM(result);
515 if (arg->
stats != NULL)
521 static rtpg_summarystats_arg
523 rtpg_summarystats_arg arg = NULL;
529 "rtpg_summarystats_arg_init: Cannot allocate memory for function arguments" 535 if (arg->
stats == NULL) {
539 "rtpg_summarystats_arg_init: Cannot allocate memory for stats function argument" 568 MemoryContext aggcontext;
569 MemoryContext oldcontext;
570 rtpg_summarystats_arg state = NULL;
571 bool skiparg =
FALSE;
584 if (!AggCheckCallContext(fcinfo, &aggcontext)) {
587 "RASTER_summaryStats_transfn: Cannot be called in a non-aggregate context" 593 oldcontext = MemoryContextSwitchTo(aggcontext);
595 if (PG_ARGISNULL(0)) {
600 MemoryContextSwitchTo(oldcontext);
603 "RASTER_summaryStats_transfn: Cannot allocate memory for state variable" 617 if (!PG_ARGISNULL(1)) {
619 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
623 if (raster == NULL) {
626 PG_FREE_IF_COPY(pgraster, 1);
628 MemoryContextSwitchTo(oldcontext);
629 elog(ERROR,
"RASTER_summaryStats_transfn: Cannot deserialize raster");
645 for (i = 2; i < nargs; i++) {
649 calltype = get_fn_expr_argtype(fcinfo->flinfo, i);
653 (calltype == INT2OID || calltype == INT4OID) &&
656 if (calltype == INT2OID)
665 if (raster != NULL) {
667 PG_FREE_IF_COPY(pgraster, 1);
670 MemoryContextSwitchTo(oldcontext);
673 "RASTER_summaryStats_transfn: Invalid band index (must use 1-based). Returning NULL" 680 calltype == BOOLOID && (
688 (calltype == FLOAT4OID || calltype == FLOAT8OID) &&
691 if (calltype == FLOAT4OID)
692 state->
sample = PG_GETARG_FLOAT4(i);
694 state->
sample = PG_GETARG_FLOAT8(i);
700 if (raster != NULL) {
702 PG_FREE_IF_COPY(pgraster, 1);
705 MemoryContextSwitchTo(oldcontext);
708 "Invalid sample percentage (must be between 0 and 1). Returning NULL" 719 if (raster != NULL) {
721 PG_FREE_IF_COPY(pgraster, 1);
724 MemoryContextSwitchTo(oldcontext);
727 "RASTER_summaryStats_transfn: Unknown function parameter at index %d",
737 if (PG_ARGISNULL(1)) {
739 MemoryContextSwitchTo(oldcontext);
740 PG_RETURN_POINTER(state);
748 "Raster does not have band at index %d. Skipping raster",
753 PG_FREE_IF_COPY(pgraster, 1);
755 MemoryContextSwitchTo(oldcontext);
756 PG_RETURN_POINTER(state);
763 NOTICE,
"Cannot find band at index %d. Skipping raster",
768 PG_FREE_IF_COPY(pgraster, 1);
770 MemoryContextSwitchTo(oldcontext);
771 PG_RETURN_POINTER(state);
778 &(state->
cK), &(state->
cM), &(state->
cQ)
783 PG_FREE_IF_COPY(pgraster, 1);
788 "Cannot compute summary statistics for band at index %d. Returning NULL",
794 MemoryContextSwitchTo(oldcontext);
798 if (stats->
count > 0) {
822 MemoryContextSwitchTo(oldcontext);
826 PG_RETURN_POINTER(state);
832 rtpg_summarystats_arg state = NULL;
836 int values_length = 6;
837 Datum values[values_length];
838 bool nulls[values_length];
844 if (!AggCheckCallContext(fcinfo, NULL)) {
845 elog(ERROR,
"RASTER_summaryStats_finalfn: Cannot be called in a non-aggregate context");
856 elog(ERROR,
"RASTER_summaryStats_finalfn: Cannot compute coverage summary stats");
872 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
875 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
877 "function returning record called in context " 878 "that cannot accept type record" 883 BlessTupleDesc(tupdesc);
885 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
887 values[0] = Int64GetDatum(state->
stats->
count);
889 values[1] = Float8GetDatum(state->
stats->
sum);
890 values[2] = Float8GetDatum(state->
stats->
mean);
892 values[4] = Float8GetDatum(state->
stats->
min);
893 values[5] = Float8GetDatum(state->
stats->
max);
904 tuple = heap_form_tuple(tupdesc, values, nulls);
907 result = HeapTupleGetDatum(tuple);
912 PG_RETURN_DATUM(result);
921 FuncCallContext *funcctx;
931 if (SRF_IS_FIRSTCALL()) {
932 MemoryContext oldcontext;
937 int32_t bandindex = 1;
941 uint32_t bin_count = 0;
942 double *bin_width = NULL;
943 uint32_t bin_width_count = 0;
965 funcctx = SRF_FIRSTCALL_INIT();
968 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
971 if (PG_ARGISNULL(0)) {
972 MemoryContextSwitchTo(oldcontext);
973 SRF_RETURN_DONE(funcctx);
975 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
979 PG_FREE_IF_COPY(pgraster, 0);
980 MemoryContextSwitchTo(oldcontext);
981 elog(ERROR,
"RASTER_histogram: Cannot deserialize raster");
982 SRF_RETURN_DONE(funcctx);
986 if (!PG_ARGISNULL(1))
987 bandindex = PG_GETARG_INT32(1);
989 if (bandindex < 1 || bandindex > num_bands) {
990 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
992 PG_FREE_IF_COPY(pgraster, 0);
993 MemoryContextSwitchTo(oldcontext);
994 SRF_RETURN_DONE(funcctx);
998 if (!PG_ARGISNULL(2))
999 exclude_nodata_value = PG_GETARG_BOOL(2);
1002 if (!PG_ARGISNULL(3)) {
1003 sample = PG_GETARG_FLOAT8(3);
1004 if (sample < 0 || sample > 1) {
1005 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
1007 PG_FREE_IF_COPY(pgraster, 0);
1008 MemoryContextSwitchTo(oldcontext);
1009 SRF_RETURN_DONE(funcctx);
1011 else if (
FLT_EQ(sample, 0.0))
1018 if (!PG_ARGISNULL(4)) {
1019 bin_count = PG_GETARG_INT32(4);
1020 if (bin_count < 1) bin_count = 0;
1024 if (!PG_ARGISNULL(5)) {
1025 array = PG_GETARG_ARRAYTYPE_P(5);
1026 etype = ARR_ELEMTYPE(array);
1027 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1035 PG_FREE_IF_COPY(pgraster, 0);
1036 MemoryContextSwitchTo(oldcontext);
1037 elog(ERROR,
"RASTER_histogram: Invalid data type for width");
1038 SRF_RETURN_DONE(funcctx);
1042 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1045 bin_width = palloc(
sizeof(
double) * n);
1046 for (i = 0, j = 0; i < n; i++) {
1047 if (nulls[i])
continue;
1051 width = (double) DatumGetFloat4(e[i]);
1054 width = (double) DatumGetFloat8(e[i]);
1058 if (width < 0 ||
FLT_EQ(width, 0.0)) {
1059 elog(NOTICE,
"Invalid value for width (must be greater than 0). Returning NULL");
1062 PG_FREE_IF_COPY(pgraster, 0);
1063 MemoryContextSwitchTo(oldcontext);
1064 SRF_RETURN_DONE(funcctx);
1067 bin_width[j] = width;
1071 bin_width_count = j;
1080 if (!PG_ARGISNULL(6))
1081 right = PG_GETARG_BOOL(6);
1084 if (!PG_ARGISNULL(7)) min = PG_GETARG_FLOAT8(7);
1087 if (!PG_ARGISNULL(8)) max = PG_GETARG_FLOAT8(8);
1092 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
1094 PG_FREE_IF_COPY(pgraster, 0);
1095 MemoryContextSwitchTo(oldcontext);
1096 SRF_RETURN_DONE(funcctx);
1103 PG_FREE_IF_COPY(pgraster, 0);
1104 if (NULL == stats || NULL == stats->
values) {
1105 elog(NOTICE,
"Cannot compute summary statistics for band at index %d", bandindex);
1106 MemoryContextSwitchTo(oldcontext);
1107 SRF_RETURN_DONE(funcctx);
1109 else if (stats->
count < 1) {
1110 elog(NOTICE,
"Cannot compute histogram for band at index %d as the band has no values", bandindex);
1111 MemoryContextSwitchTo(oldcontext);
1112 SRF_RETURN_DONE(funcctx);
1116 hist =
rt_band_get_histogram(stats, bin_count, bin_width, bin_width_count, right, min, max, &count);
1117 if (bin_width_count) pfree(bin_width);
1119 if (NULL == hist || !count) {
1120 elog(NOTICE,
"Cannot compute histogram for band at index %d", bandindex);
1121 MemoryContextSwitchTo(oldcontext);
1122 SRF_RETURN_DONE(funcctx);
1128 funcctx->user_fctx = hist;
1131 funcctx->max_calls =
count;
1134 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
1136 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1138 "function returning record called in context " 1139 "that cannot accept type record" 1144 BlessTupleDesc(tupdesc);
1145 funcctx->tuple_desc = tupdesc;
1147 MemoryContextSwitchTo(oldcontext);
1151 funcctx = SRF_PERCALL_SETUP();
1153 call_cntr = funcctx->call_cntr;
1154 max_calls = funcctx->max_calls;
1155 tupdesc = funcctx->tuple_desc;
1156 hist2 = funcctx->user_fctx;
1159 if (call_cntr < max_calls) {
1160 int values_length = 4;
1161 Datum values[values_length];
1162 bool nulls[values_length];
1168 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
1170 values[0] = Float8GetDatum(hist2[call_cntr].min);
1171 values[1] = Float8GetDatum(hist2[call_cntr].max);
1172 values[2] = Int64GetDatum(hist2[call_cntr].
count);
1173 values[3] = Float8GetDatum(hist2[call_cntr].percent);
1176 tuple = heap_form_tuple(tupdesc, values, nulls);
1179 result = HeapTupleGetDatum(tuple);
1181 SRF_RETURN_NEXT(funcctx, result);
1186 SRF_RETURN_DONE(funcctx);
1196 FuncCallContext *funcctx;
1208 if (SRF_IS_FIRSTCALL()) {
1209 MemoryContext oldcontext;
1211 text *tablenametext = NULL;
1212 char *tablename = NULL;
1213 text *colnametext = NULL;
1214 char *colname = NULL;
1215 int32_t bandindex = 1;
1218 uint32_t bin_count = 0;
1219 double *bin_width = NULL;
1220 uint32_t bin_width_count = 0;
1232 SPITupleTable *tuptable = NULL;
1235 bool isNull =
FALSE;
1259 funcctx = SRF_FIRSTCALL_INIT();
1262 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1265 if (PG_ARGISNULL(0)) {
1266 elog(NOTICE,
"Table name must be provided");
1267 MemoryContextSwitchTo(oldcontext);
1268 SRF_RETURN_DONE(funcctx);
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);
1280 if (PG_ARGISNULL(1)) {
1281 elog(NOTICE,
"Column name must be provided");
1282 MemoryContextSwitchTo(oldcontext);
1283 SRF_RETURN_DONE(funcctx);
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);
1295 if (!PG_ARGISNULL(2))
1296 bandindex = PG_GETARG_INT32(2);
1299 if (!PG_ARGISNULL(3))
1300 exclude_nodata_value = PG_GETARG_BOOL(3);
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);
1310 else if (
FLT_EQ(sample, 0.0))
1317 if (!PG_ARGISNULL(5)) {
1318 bin_count = PG_GETARG_INT32(5);
1319 if (bin_count < 1) bin_count = 0;
1323 if (!PG_ARGISNULL(6)) {
1324 array = PG_GETARG_ARRAYTYPE_P(6);
1325 etype = ARR_ELEMTYPE(array);
1326 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1333 MemoryContextSwitchTo(oldcontext);
1334 elog(ERROR,
"RASTER_histogramCoverage: Invalid data type for width");
1335 SRF_RETURN_DONE(funcctx);
1339 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1342 bin_width = palloc(
sizeof(
double) * n);
1343 for (i = 0, j = 0; i < n; i++) {
1344 if (nulls[i])
continue;
1348 width = (double) DatumGetFloat4(e[i]);
1351 width = (double) DatumGetFloat8(e[i]);
1355 if (width < 0 ||
FLT_EQ(width, 0.0)) {
1356 elog(NOTICE,
"Invalid value for width (must be greater than 0). Returning NULL");
1358 MemoryContextSwitchTo(oldcontext);
1359 SRF_RETURN_DONE(funcctx);
1362 bin_width[j] = width;
1366 bin_width_count = j;
1375 if (!PG_ARGISNULL(7))
1376 right = PG_GETARG_BOOL(7);
1379 spi_result = SPI_connect();
1380 if (spi_result != SPI_OK_CONNECT) {
1382 if (bin_width_count) pfree(bin_width);
1384 MemoryContextSwitchTo(oldcontext);
1385 elog(ERROR,
"RASTER_histogramCoverage: Cannot connect to database using SPI");
1386 SRF_RETURN_DONE(funcctx);
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);
1394 if (SPI_tuptable) SPI_freetuptable(tuptable);
1397 if (bin_width_count) pfree(bin_width);
1399 MemoryContextSwitchTo(oldcontext);
1400 elog(ERROR,
"RASTER_histogramCoverage: Cannot allocate memory for sql");
1401 SRF_RETURN_DONE(funcctx);
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);
1407 spi_result = SPI_execute(sql,
TRUE, 0);
1409 if (spi_result != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
1411 if (SPI_tuptable) SPI_freetuptable(tuptable);
1414 if (bin_width_count) pfree(bin_width);
1416 MemoryContextSwitchTo(oldcontext);
1417 elog(ERROR,
"RASTER_histogramCoverage: Cannot get summary stats of coverage");
1418 SRF_RETURN_DONE(funcctx);
1421 tupdesc = SPI_tuptable->tupdesc;
1422 tuptable = SPI_tuptable;
1423 tuple = tuptable->vals[0];
1425 tmp = SPI_getvalue(tuple, tupdesc, 1);
1426 if (NULL == tmp || !strlen(tmp)) {
1428 if (SPI_tuptable) SPI_freetuptable(tuptable);
1431 if (bin_width_count) pfree(bin_width);
1433 MemoryContextSwitchTo(oldcontext);
1434 elog(ERROR,
"RASTER_histogramCoverage: Cannot get summary stats of coverage");
1435 SRF_RETURN_DONE(funcctx);
1437 min = strtod(tmp, NULL);
1441 tmp = SPI_getvalue(tuple, tupdesc, 2);
1442 if (NULL == tmp || !strlen(tmp)) {
1444 if (SPI_tuptable) SPI_freetuptable(tuptable);
1447 if (bin_width_count) pfree(bin_width);
1449 MemoryContextSwitchTo(oldcontext);
1450 elog(ERROR,
"RASTER_histogramCoverage: Cannot get summary stats of coverage");
1451 SRF_RETURN_DONE(funcctx);
1453 max = strtod(tmp, NULL);
1459 len =
sizeof(char) * (strlen(
"SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
1460 sql = (
char *) palloc(len);
1463 if (SPI_tuptable) SPI_freetuptable(tuptable);
1466 if (bin_width_count) pfree(bin_width);
1468 MemoryContextSwitchTo(oldcontext);
1469 elog(ERROR,
"RASTER_histogramCoverage: Cannot allocate memory for sql");
1470 SRF_RETURN_DONE(funcctx);
1474 snprintf(sql, len,
"SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
1476 portal = SPI_cursor_open_with_args(
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];
1492 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
1493 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
1495 if (SPI_tuptable) SPI_freetuptable(tuptable);
1496 SPI_cursor_close(portal);
1499 if (NULL != covhist) pfree(covhist);
1500 if (bin_width_count) pfree(bin_width);
1502 MemoryContextSwitchTo(oldcontext);
1503 elog(ERROR,
"RASTER_histogramCoverage: Cannot get raster of coverage");
1504 SRF_RETURN_DONE(funcctx);
1507 SPI_cursor_fetch(portal,
TRUE, 1);
1511 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
1516 if (SPI_tuptable) SPI_freetuptable(tuptable);
1517 SPI_cursor_close(portal);
1520 if (NULL != covhist) pfree(covhist);
1521 if (bin_width_count) pfree(bin_width);
1523 MemoryContextSwitchTo(oldcontext);
1524 elog(ERROR,
"RASTER_histogramCoverage: Cannot deserialize raster");
1525 SRF_RETURN_DONE(funcctx);
1530 if (bandindex < 1 || bandindex > num_bands) {
1531 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
1535 if (SPI_tuptable) SPI_freetuptable(tuptable);
1536 SPI_cursor_close(portal);
1539 if (NULL != covhist) pfree(covhist);
1540 if (bin_width_count) pfree(bin_width);
1542 MemoryContextSwitchTo(oldcontext);
1543 SRF_RETURN_DONE(funcctx);
1549 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
1553 if (SPI_tuptable) SPI_freetuptable(tuptable);
1554 SPI_cursor_close(portal);
1557 if (NULL != covhist) pfree(covhist);
1558 if (bin_width_count) pfree(bin_width);
1560 MemoryContextSwitchTo(oldcontext);
1561 SRF_RETURN_DONE(funcctx);
1570 if (NULL == stats) {
1571 elog(NOTICE,
"Cannot compute summary statistics for band at index %d. Returning NULL", bandindex);
1573 if (SPI_tuptable) SPI_freetuptable(tuptable);
1574 SPI_cursor_close(portal);
1577 if (NULL != covhist) pfree(covhist);
1578 if (bin_width_count) pfree(bin_width);
1580 MemoryContextSwitchTo(oldcontext);
1581 SRF_RETURN_DONE(funcctx);
1585 if (stats->
count > 0) {
1586 hist =
rt_band_get_histogram(stats, bin_count, bin_width, bin_width_count, right, min, max, &count);
1588 if (NULL == hist || !count) {
1589 elog(NOTICE,
"Cannot compute histogram for band at index %d", bandindex);
1591 if (SPI_tuptable) SPI_freetuptable(tuptable);
1592 SPI_cursor_close(portal);
1595 if (NULL != covhist) pfree(covhist);
1596 if (bin_width_count) pfree(bin_width);
1598 MemoryContextSwitchTo(oldcontext);
1599 SRF_RETURN_DONE(funcctx);
1605 if (NULL == covhist) {
1607 if (NULL == covhist) {
1610 if (SPI_tuptable) SPI_freetuptable(tuptable);
1611 SPI_cursor_close(portal);
1614 if (bin_width_count) pfree(bin_width);
1616 MemoryContextSwitchTo(oldcontext);
1617 elog(ERROR,
"RASTER_histogramCoverage: Cannot allocate memory for histogram of coverage");
1618 SRF_RETURN_DONE(funcctx);
1621 for (i = 0; i <
count; i++) {
1622 sum += hist[i].
count;
1625 covhist[i].
min = hist[i].
min;
1626 covhist[i].
max = hist[i].
max;
1630 for (i = 0; i <
count; i++) {
1631 sum += hist[i].
count;
1639 if (bin_count <= 0) bin_count =
count;
1643 SPI_cursor_fetch(portal,
TRUE, 1);
1646 if (SPI_tuptable) SPI_freetuptable(tuptable);
1647 SPI_cursor_close(portal);
1650 if (bin_width_count) pfree(bin_width);
1654 for (i = 0; i <
count; i++)
1655 covhist[i].percent = covhist[i].count / (
double) sum;
1659 funcctx->user_fctx = covhist;
1662 funcctx->max_calls =
count;
1665 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
1667 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1669 "function returning record called in context " 1670 "that cannot accept type record" 1675 BlessTupleDesc(tupdesc);
1676 funcctx->tuple_desc = tupdesc;
1678 MemoryContextSwitchTo(oldcontext);
1682 funcctx = SRF_PERCALL_SETUP();
1684 call_cntr = funcctx->call_cntr;
1685 max_calls = funcctx->max_calls;
1686 tupdesc = funcctx->tuple_desc;
1687 covhist2 = funcctx->user_fctx;
1690 if (call_cntr < max_calls) {
1691 int values_length = 4;
1692 Datum values[values_length];
1693 bool nulls[values_length];
1699 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
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);
1707 tuple = heap_form_tuple(tupdesc, values, nulls);
1710 result = HeapTupleGetDatum(tuple);
1712 SRF_RETURN_NEXT(funcctx, result);
1717 SRF_RETURN_DONE(funcctx);
1727 FuncCallContext *funcctx;
1737 if (SRF_IS_FIRSTCALL()) {
1738 MemoryContext oldcontext;
1743 int32_t bandindex = 0;
1747 double *quantiles = NULL;
1748 uint32_t quantiles_count = 0;
1749 double quantile = 0;
1765 funcctx = SRF_FIRSTCALL_INIT();
1768 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1771 if (PG_ARGISNULL(0)) {
1772 MemoryContextSwitchTo(oldcontext);
1773 SRF_RETURN_DONE(funcctx);
1775 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1779 PG_FREE_IF_COPY(pgraster, 0);
1780 MemoryContextSwitchTo(oldcontext);
1781 elog(ERROR,
"RASTER_quantile: Cannot deserialize raster");
1782 SRF_RETURN_DONE(funcctx);
1786 bandindex = PG_GETARG_INT32(1);
1788 if (bandindex < 1 || bandindex > num_bands) {
1789 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
1791 PG_FREE_IF_COPY(pgraster, 0);
1792 MemoryContextSwitchTo(oldcontext);
1793 SRF_RETURN_DONE(funcctx);
1797 if (!PG_ARGISNULL(2))
1798 exclude_nodata_value = PG_GETARG_BOOL(2);
1801 if (!PG_ARGISNULL(3)) {
1802 sample = PG_GETARG_FLOAT8(3);
1803 if (sample < 0 || sample > 1) {
1804 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
1806 PG_FREE_IF_COPY(pgraster, 0);
1807 MemoryContextSwitchTo(oldcontext);
1808 SRF_RETURN_DONE(funcctx);
1810 else if (
FLT_EQ(sample, 0.0))
1817 if (!PG_ARGISNULL(4)) {
1818 array = PG_GETARG_ARRAYTYPE_P(4);
1819 etype = ARR_ELEMTYPE(array);
1820 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1828 PG_FREE_IF_COPY(pgraster, 0);
1829 MemoryContextSwitchTo(oldcontext);
1830 elog(ERROR,
"RASTER_quantile: Invalid data type for quantiles");
1831 SRF_RETURN_DONE(funcctx);
1835 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1838 quantiles = palloc(
sizeof(
double) * n);
1839 for (i = 0, j = 0; i < n; i++) {
1840 if (nulls[i])
continue;
1844 quantile = (double) DatumGetFloat4(e[i]);
1847 quantile = (double) DatumGetFloat8(e[i]);
1851 if (quantile < 0 || quantile > 1) {
1852 elog(NOTICE,
"Invalid value for quantile (must be between 0 and 1). Returning NULL");
1855 PG_FREE_IF_COPY(pgraster, 0);
1856 MemoryContextSwitchTo(oldcontext);
1857 SRF_RETURN_DONE(funcctx);
1860 quantiles[j] = quantile;
1864 quantiles_count = j;
1875 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
1877 PG_FREE_IF_COPY(pgraster, 0);
1878 MemoryContextSwitchTo(oldcontext);
1879 SRF_RETURN_DONE(funcctx);
1886 PG_FREE_IF_COPY(pgraster, 0);
1887 if (NULL == stats || NULL == stats->
values) {
1888 elog(NOTICE,
"Cannot retrieve summary statistics for band at index %d", bandindex);
1889 MemoryContextSwitchTo(oldcontext);
1890 SRF_RETURN_DONE(funcctx);
1892 else if (stats->
count < 1) {
1893 elog(NOTICE,
"Cannot compute quantiles for band at index %d as the band has no values", bandindex);
1894 MemoryContextSwitchTo(oldcontext);
1895 SRF_RETURN_DONE(funcctx);
1900 if (quantiles_count) pfree(quantiles);
1902 if (NULL == quant || !count) {
1903 elog(NOTICE,
"Cannot compute quantiles for band at index %d", bandindex);
1904 MemoryContextSwitchTo(oldcontext);
1905 SRF_RETURN_DONE(funcctx);
1911 funcctx->user_fctx = quant;
1914 funcctx->max_calls =
count;
1917 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
1919 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1921 "function returning record called in context " 1922 "that cannot accept type record" 1927 BlessTupleDesc(tupdesc);
1928 funcctx->tuple_desc = tupdesc;
1930 MemoryContextSwitchTo(oldcontext);
1934 funcctx = SRF_PERCALL_SETUP();
1936 call_cntr = funcctx->call_cntr;
1937 max_calls = funcctx->max_calls;
1938 tupdesc = funcctx->tuple_desc;
1939 quant2 = funcctx->user_fctx;
1942 if (call_cntr < max_calls) {
1943 int values_length = 2;
1944 Datum values[values_length];
1945 bool nulls[values_length];
1951 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
1953 values[0] = Float8GetDatum(quant2[call_cntr].quantile);
1954 values[1] = Float8GetDatum(quant2[call_cntr].
value);
1957 tuple = heap_form_tuple(tupdesc, values, nulls);
1960 result = HeapTupleGetDatum(tuple);
1962 SRF_RETURN_NEXT(funcctx, result);
1967 SRF_RETURN_DONE(funcctx);
1977 FuncCallContext *funcctx;
1989 if (SRF_IS_FIRSTCALL()) {
1990 MemoryContext oldcontext;
1992 text *tablenametext = NULL;
1993 char *tablename = NULL;
1994 text *colnametext = NULL;
1995 char *colname = NULL;
1996 int32_t bandindex = 1;
1999 double *quantiles = NULL;
2000 uint32_t quantiles_count = 0;
2001 double quantile = 0;
2007 uint64_t cov_count = 0;
2010 SPITupleTable *tuptable = NULL;
2013 bool isNull =
FALSE;
2020 uint32_t qlls_count;
2036 funcctx = SRF_FIRSTCALL_INIT();
2039 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2042 if (PG_ARGISNULL(0)) {
2043 elog(NOTICE,
"Table name must be provided");
2044 MemoryContextSwitchTo(oldcontext);
2045 SRF_RETURN_DONE(funcctx);
2047 tablenametext = PG_GETARG_TEXT_P(0);
2048 tablename = text_to_cstring(tablenametext);
2049 if (!strlen(tablename)) {
2050 elog(NOTICE,
"Table name must be provided");
2051 MemoryContextSwitchTo(oldcontext);
2052 SRF_RETURN_DONE(funcctx);
2057 if (PG_ARGISNULL(1)) {
2058 elog(NOTICE,
"Column name must be provided");
2059 MemoryContextSwitchTo(oldcontext);
2060 SRF_RETURN_DONE(funcctx);
2062 colnametext = PG_GETARG_TEXT_P(1);
2063 colname = text_to_cstring(colnametext);
2064 if (!strlen(colname)) {
2065 elog(NOTICE,
"Column name must be provided");
2066 MemoryContextSwitchTo(oldcontext);
2067 SRF_RETURN_DONE(funcctx);
2072 if (!PG_ARGISNULL(2))
2073 bandindex = PG_GETARG_INT32(2);
2076 if (!PG_ARGISNULL(3))
2077 exclude_nodata_value = PG_GETARG_BOOL(3);
2080 if (!PG_ARGISNULL(4)) {
2081 sample = PG_GETARG_FLOAT8(4);
2082 if (sample < 0 || sample > 1) {
2083 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
2084 MemoryContextSwitchTo(oldcontext);
2085 SRF_RETURN_DONE(funcctx);
2087 else if (
FLT_EQ(sample, 0.0))
2094 if (!PG_ARGISNULL(5)) {
2095 array = PG_GETARG_ARRAYTYPE_P(5);
2096 etype = ARR_ELEMTYPE(array);
2097 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2104 MemoryContextSwitchTo(oldcontext);
2105 elog(ERROR,
"RASTER_quantileCoverage: Invalid data type for quantiles");
2106 SRF_RETURN_DONE(funcctx);
2110 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
2113 quantiles = palloc(
sizeof(
double) * n);
2114 for (i = 0, j = 0; i < n; i++) {
2115 if (nulls[i])
continue;
2119 quantile = (double) DatumGetFloat4(e[i]);
2122 quantile = (double) DatumGetFloat8(e[i]);
2126 if (quantile < 0 || quantile > 1) {
2127 elog(NOTICE,
"Invalid value for quantile (must be between 0 and 1). Returning NULL");
2129 MemoryContextSwitchTo(oldcontext);
2130 SRF_RETURN_DONE(funcctx);
2137 quantiles_count = j;
2147 spi_result = SPI_connect();
2148 if (spi_result != SPI_OK_CONNECT) {
2149 MemoryContextSwitchTo(oldcontext);
2150 elog(ERROR,
"RASTER_quantileCoverage: Cannot connect to database using SPI");
2151 SRF_RETURN_DONE(funcctx);
2154 len =
sizeof(char) * (strlen(
"SELECT count FROM _st_summarystats('','',,::boolean,)") + strlen(tablename) + strlen(colname) + (
MAX_INT_CHARLEN * 2) +
MAX_DBL_CHARLEN + 1);
2155 sql = (
char *) palloc(len);
2158 if (SPI_tuptable) SPI_freetuptable(tuptable);
2161 MemoryContextSwitchTo(oldcontext);
2162 elog(ERROR,
"RASTER_quantileCoverage: Cannot allocate memory for sql");
2163 SRF_RETURN_DONE(funcctx);
2167 snprintf(sql, len,
"SELECT count FROM _st_summarystats('%s','%s',%d,%d::boolean,%f)", tablename, colname, bandindex, (exclude_nodata_value ? 1 : 0), sample);
2169 spi_result = SPI_execute(sql,
TRUE, 0);
2171 if (spi_result != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
2173 if (SPI_tuptable) SPI_freetuptable(tuptable);
2176 MemoryContextSwitchTo(oldcontext);
2177 elog(ERROR,
"RASTER_quantileCoverage: Cannot get summary stats of coverage");
2178 SRF_RETURN_DONE(funcctx);
2181 tupdesc = SPI_tuptable->tupdesc;
2182 tuptable = SPI_tuptable;
2183 tuple = tuptable->vals[0];
2185 tmp = SPI_getvalue(tuple, tupdesc, 1);
2186 if (NULL == tmp || !strlen(tmp)) {
2188 if (SPI_tuptable) SPI_freetuptable(tuptable);
2191 MemoryContextSwitchTo(oldcontext);
2192 elog(ERROR,
"RASTER_quantileCoverage: Cannot get summary stats of coverage");
2193 SRF_RETURN_DONE(funcctx);
2195 cov_count = strtol(tmp, NULL, 10);
2201 len =
sizeof(char) * (strlen(
"SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
2202 sql = (
char *) palloc(len);
2205 if (SPI_tuptable) SPI_freetuptable(tuptable);
2208 MemoryContextSwitchTo(oldcontext);
2209 elog(ERROR,
"RASTER_quantileCoverage: Cannot allocate memory for sql");
2210 SRF_RETURN_DONE(funcctx);
2214 snprintf(sql, len,
"SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
2216 portal = SPI_cursor_open_with_args(
2226 SPI_cursor_fetch(portal,
TRUE, 1);
2227 while (SPI_processed == 1 && SPI_tuptable != NULL) {
2228 if (NULL != covquant) pfree(covquant);
2230 tupdesc = SPI_tuptable->tupdesc;
2231 tuptable = SPI_tuptable;
2232 tuple = tuptable->vals[0];
2234 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
2235 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
2237 if (SPI_tuptable) SPI_freetuptable(tuptable);
2238 SPI_cursor_close(portal);
2241 MemoryContextSwitchTo(oldcontext);
2242 elog(ERROR,
"RASTER_quantileCoverage: Cannot get raster of coverage");
2243 SRF_RETURN_DONE(funcctx);
2246 SPI_cursor_fetch(portal,
TRUE, 1);
2250 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
2255 if (SPI_tuptable) SPI_freetuptable(tuptable);
2256 SPI_cursor_close(portal);
2259 MemoryContextSwitchTo(oldcontext);
2260 elog(ERROR,
"RASTER_quantileCoverage: Cannot deserialize raster");
2261 SRF_RETURN_DONE(funcctx);
2266 if (bandindex < 1 || bandindex > num_bands) {
2267 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
2271 if (SPI_tuptable) SPI_freetuptable(tuptable);
2272 SPI_cursor_close(portal);
2275 MemoryContextSwitchTo(oldcontext);
2276 SRF_RETURN_DONE(funcctx);
2282 elog(NOTICE,
"Cannot find raster band of index %d. Returning NULL", bandindex);
2286 if (SPI_tuptable) SPI_freetuptable(tuptable);
2287 SPI_cursor_close(portal);
2290 MemoryContextSwitchTo(oldcontext);
2291 SRF_RETURN_DONE(funcctx);
2296 exclude_nodata_value, sample, cov_count,
2298 quantiles, quantiles_count,
2305 if (NULL == covquant || !count) {
2306 elog(NOTICE,
"Cannot compute quantiles for band at index %d", bandindex);
2308 if (SPI_tuptable) SPI_freetuptable(tuptable);
2309 SPI_cursor_close(portal);
2312 MemoryContextSwitchTo(oldcontext);
2313 SRF_RETURN_DONE(funcctx);
2317 SPI_cursor_fetch(portal,
TRUE, 1);
2320 covquant2 = SPI_palloc(
sizeof(
struct rt_quantile_t) * count);
2321 for (i = 0; i <
count; i++) {
2324 if (covquant2[i].has_value)
2328 if (NULL != covquant) pfree(covquant);
2331 if (SPI_tuptable) SPI_freetuptable(tuptable);
2332 SPI_cursor_close(portal);
2335 if (quantiles_count) pfree(quantiles);
2340 funcctx->user_fctx = covquant2;
2343 funcctx->max_calls =
count;
2346 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
2348 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2350 "function returning record called in context " 2351 "that cannot accept type record" 2356 BlessTupleDesc(tupdesc);
2357 funcctx->tuple_desc = tupdesc;
2359 MemoryContextSwitchTo(oldcontext);
2363 funcctx = SRF_PERCALL_SETUP();
2365 call_cntr = funcctx->call_cntr;
2366 max_calls = funcctx->max_calls;
2367 tupdesc = funcctx->tuple_desc;
2368 covquant2 = funcctx->user_fctx;
2371 if (call_cntr < max_calls) {
2372 int values_length = 2;
2373 Datum values[values_length];
2374 bool nulls[values_length];
2380 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
2382 values[0] = Float8GetDatum(covquant2[call_cntr].
quantile);
2383 if (covquant2[call_cntr].has_value)
2384 values[1] = Float8GetDatum(covquant2[call_cntr].
value);
2389 tuple = heap_form_tuple(tupdesc, values, nulls);
2392 result = HeapTupleGetDatum(tuple);
2394 SRF_RETURN_NEXT(funcctx, result);
2400 SRF_RETURN_DONE(funcctx);
2407 FuncCallContext *funcctx;
2417 if (SRF_IS_FIRSTCALL()) {
2418 MemoryContext oldcontext;
2423 int32_t bandindex = 0;
2426 double *search_values = NULL;
2427 uint32_t search_values_count = 0;
2443 funcctx = SRF_FIRSTCALL_INIT();
2446 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2449 if (PG_ARGISNULL(0)) {
2450 MemoryContextSwitchTo(oldcontext);
2451 SRF_RETURN_DONE(funcctx);
2453 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2457 PG_FREE_IF_COPY(pgraster, 0);
2458 MemoryContextSwitchTo(oldcontext);
2459 elog(ERROR,
"RASTER_valueCount: Cannot deserialize raster");
2460 SRF_RETURN_DONE(funcctx);
2464 bandindex = PG_GETARG_INT32(1);
2466 if (bandindex < 1 || bandindex > num_bands) {
2467 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
2469 PG_FREE_IF_COPY(pgraster, 0);
2470 MemoryContextSwitchTo(oldcontext);
2471 SRF_RETURN_DONE(funcctx);
2475 if (!PG_ARGISNULL(2))
2476 exclude_nodata_value = PG_GETARG_BOOL(2);
2479 if (!PG_ARGISNULL(3)) {
2480 array = PG_GETARG_ARRAYTYPE_P(3);
2481 etype = ARR_ELEMTYPE(array);
2482 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2490 PG_FREE_IF_COPY(pgraster, 0);
2491 MemoryContextSwitchTo(oldcontext);
2492 elog(ERROR,
"RASTER_valueCount: Invalid data type for values");
2493 SRF_RETURN_DONE(funcctx);
2497 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
2500 search_values = palloc(
sizeof(
double) * n);
2501 for (i = 0, j = 0; i < n; i++) {
2502 if (nulls[i])
continue;
2506 search_values[j] = (double) DatumGetFloat4(e[i]);
2509 search_values[j] = (double) DatumGetFloat8(e[i]);
2516 search_values_count = j;
2519 pfree(search_values);
2520 search_values = NULL;
2525 if (!PG_ARGISNULL(4)) {
2526 roundto = PG_GETARG_FLOAT8(4);
2527 if (roundto < 0.) roundto = 0;
2533 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
2535 PG_FREE_IF_COPY(pgraster, 0);
2536 MemoryContextSwitchTo(oldcontext);
2537 SRF_RETURN_DONE(funcctx);
2541 vcnts =
rt_band_get_value_count(band, (
int) exclude_nodata_value, search_values, search_values_count, roundto, NULL, &count);
2544 PG_FREE_IF_COPY(pgraster, 0);
2545 if (NULL == vcnts || !count) {
2546 elog(NOTICE,
"Cannot count the values for band at index %d", bandindex);
2547 MemoryContextSwitchTo(oldcontext);
2548 SRF_RETURN_DONE(funcctx);
2554 funcctx->user_fctx = vcnts;
2557 funcctx->max_calls =
count;
2560 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
2562 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2564 "function returning record called in context " 2565 "that cannot accept type record" 2570 BlessTupleDesc(tupdesc);
2571 funcctx->tuple_desc = tupdesc;
2573 MemoryContextSwitchTo(oldcontext);
2577 funcctx = SRF_PERCALL_SETUP();
2579 call_cntr = funcctx->call_cntr;
2580 max_calls = funcctx->max_calls;
2581 tupdesc = funcctx->tuple_desc;
2582 vcnts2 = funcctx->user_fctx;
2585 if (call_cntr < max_calls) {
2586 int values_length = 3;
2587 Datum values[values_length];
2588 bool nulls[values_length];
2594 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
2596 values[0] = Float8GetDatum(vcnts2[call_cntr].
value);
2597 values[1] = UInt32GetDatum(vcnts2[call_cntr].
count);
2598 values[2] = Float8GetDatum(vcnts2[call_cntr].percent);
2601 tuple = heap_form_tuple(tupdesc, values, nulls);
2604 result = HeapTupleGetDatum(tuple);
2606 SRF_RETURN_NEXT(funcctx, result);
2611 SRF_RETURN_DONE(funcctx);
2618 FuncCallContext *funcctx;
2622 uint64_t covcount = 0;
2623 uint64_t covtotal = 0;
2632 if (SRF_IS_FIRSTCALL()) {
2633 MemoryContext oldcontext;
2635 text *tablenametext = NULL;
2636 char *tablename = NULL;
2637 text *colnametext = NULL;
2638 char *colname = NULL;
2639 int32_t bandindex = 1;
2641 double *search_values = NULL;
2642 uint32_t search_values_count = 0;
2649 SPITupleTable *tuptable = NULL;
2652 bool isNull =
FALSE;
2674 funcctx = SRF_FIRSTCALL_INIT();
2677 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2680 if (PG_ARGISNULL(0)) {
2681 elog(NOTICE,
"Table name must be provided");
2682 MemoryContextSwitchTo(oldcontext);
2683 SRF_RETURN_DONE(funcctx);
2685 tablenametext = PG_GETARG_TEXT_P(0);
2686 tablename = text_to_cstring(tablenametext);
2687 if (!strlen(tablename)) {
2688 elog(NOTICE,
"Table name must be provided");
2689 MemoryContextSwitchTo(oldcontext);
2690 SRF_RETURN_DONE(funcctx);
2695 if (PG_ARGISNULL(1)) {
2696 elog(NOTICE,
"Column name must be provided");
2697 MemoryContextSwitchTo(oldcontext);
2698 SRF_RETURN_DONE(funcctx);
2700 colnametext = PG_GETARG_TEXT_P(1);
2701 colname = text_to_cstring(colnametext);
2702 if (!strlen(colname)) {
2703 elog(NOTICE,
"Column name must be provided");
2704 MemoryContextSwitchTo(oldcontext);
2705 SRF_RETURN_DONE(funcctx);
2710 if (!PG_ARGISNULL(2))
2711 bandindex = PG_GETARG_INT32(2);
2714 if (!PG_ARGISNULL(3))
2715 exclude_nodata_value = PG_GETARG_BOOL(3);
2718 if (!PG_ARGISNULL(4)) {
2719 array = PG_GETARG_ARRAYTYPE_P(4);
2720 etype = ARR_ELEMTYPE(array);
2721 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2728 MemoryContextSwitchTo(oldcontext);
2729 elog(ERROR,
"RASTER_valueCountCoverage: Invalid data type for values");
2730 SRF_RETURN_DONE(funcctx);
2734 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
2737 search_values = palloc(
sizeof(
double) * n);
2738 for (i = 0, j = 0; i < n; i++) {
2739 if (nulls[i])
continue;
2743 search_values[j] = (double) DatumGetFloat4(e[i]);
2746 search_values[j] = (double) DatumGetFloat8(e[i]);
2753 search_values_count = j;
2756 pfree(search_values);
2757 search_values = NULL;
2762 if (!PG_ARGISNULL(5)) {
2763 roundto = PG_GETARG_FLOAT8(5);
2764 if (roundto < 0.) roundto = 0;
2769 spi_result = SPI_connect();
2770 if (spi_result != SPI_OK_CONNECT) {
2772 if (search_values_count) pfree(search_values);
2774 MemoryContextSwitchTo(oldcontext);
2775 elog(ERROR,
"RASTER_valueCountCoverage: Cannot connect to database using SPI");
2776 SRF_RETURN_DONE(funcctx);
2780 len =
sizeof(char) * (strlen(
"SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
2781 sql = (
char *) palloc(len);
2784 if (SPI_tuptable) SPI_freetuptable(tuptable);
2787 if (search_values_count) pfree(search_values);
2789 MemoryContextSwitchTo(oldcontext);
2790 elog(ERROR,
"RASTER_valueCountCoverage: Cannot allocate memory for sql");
2791 SRF_RETURN_DONE(funcctx);
2795 snprintf(sql, len,
"SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
2797 portal = SPI_cursor_open_with_args(
2807 SPI_cursor_fetch(portal,
TRUE, 1);
2808 while (SPI_processed == 1 && SPI_tuptable != NULL) {
2809 tupdesc = SPI_tuptable->tupdesc;
2810 tuptable = SPI_tuptable;
2811 tuple = tuptable->vals[0];
2813 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
2814 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
2816 if (SPI_tuptable) SPI_freetuptable(tuptable);
2817 SPI_cursor_close(portal);
2820 if (NULL != covvcnts) pfree(covvcnts);
2821 if (search_values_count) pfree(search_values);
2823 MemoryContextSwitchTo(oldcontext);
2824 elog(ERROR,
"RASTER_valueCountCoverage: Cannot get raster of coverage");
2825 SRF_RETURN_DONE(funcctx);
2828 SPI_cursor_fetch(portal,
TRUE, 1);
2832 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
2837 if (SPI_tuptable) SPI_freetuptable(tuptable);
2838 SPI_cursor_close(portal);
2841 if (NULL != covvcnts) pfree(covvcnts);
2842 if (search_values_count) pfree(search_values);
2844 MemoryContextSwitchTo(oldcontext);
2845 elog(ERROR,
"RASTER_valueCountCoverage: Cannot deserialize raster");
2846 SRF_RETURN_DONE(funcctx);
2851 if (bandindex < 1 || bandindex > num_bands) {
2852 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
2856 if (SPI_tuptable) SPI_freetuptable(tuptable);
2857 SPI_cursor_close(portal);
2860 if (NULL != covvcnts) pfree(covvcnts);
2861 if (search_values_count) pfree(search_values);
2863 MemoryContextSwitchTo(oldcontext);
2864 SRF_RETURN_DONE(funcctx);
2870 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
2874 if (SPI_tuptable) SPI_freetuptable(tuptable);
2875 SPI_cursor_close(portal);
2878 if (NULL != covvcnts) pfree(covvcnts);
2879 if (search_values_count) pfree(search_values);
2881 MemoryContextSwitchTo(oldcontext);
2882 SRF_RETURN_DONE(funcctx);
2886 vcnts =
rt_band_get_value_count(band, (
int) exclude_nodata_value, search_values, search_values_count, roundto, &total, &count);
2889 if (NULL == vcnts || !count) {
2890 elog(NOTICE,
"Cannot count the values for band at index %d", bandindex);
2892 if (SPI_tuptable) SPI_freetuptable(tuptable);
2893 SPI_cursor_close(portal);
2896 if (NULL != covvcnts)
free(covvcnts);
2897 if (search_values_count) pfree(search_values);
2899 MemoryContextSwitchTo(oldcontext);
2900 SRF_RETURN_DONE(funcctx);
2905 if (NULL == covvcnts) {
2907 if (NULL == covvcnts) {
2909 if (SPI_tuptable) SPI_freetuptable(tuptable);
2910 SPI_cursor_close(portal);
2913 if (search_values_count) pfree(search_values);
2915 MemoryContextSwitchTo(oldcontext);
2916 elog(ERROR,
"RASTER_valueCountCoverage: Cannot allocate memory for value counts of coverage");
2917 SRF_RETURN_DONE(funcctx);
2920 for (i = 0; i <
count; i++) {
2929 for (i = 0; i <
count; i++) {
2932 for (j = 0; j < covcount; j++) {
2944 covvcnts = SPI_repalloc(covvcnts,
sizeof(
struct rt_valuecount_t) * covcount);
2945 if (NULL == covvcnts) {
2947 if (SPI_tuptable) SPI_freetuptable(tuptable);
2948 SPI_cursor_close(portal);
2951 if (search_values_count) pfree(search_values);
2952 if (NULL != covvcnts)
free(covvcnts);
2954 MemoryContextSwitchTo(oldcontext);
2955 elog(ERROR,
"RASTER_valueCountCoverage: Cannot change allocated memory for value counts of coverage");
2956 SRF_RETURN_DONE(funcctx);
2959 covvcnts[covcount - 1].
value = vcnts[i].
value;
2960 covvcnts[covcount - 1].
count = vcnts[i].
count;
2961 covvcnts[covcount - 1].
percent = -1;
2971 SPI_cursor_fetch(portal,
TRUE, 1);
2974 if (SPI_tuptable) SPI_freetuptable(tuptable);
2975 SPI_cursor_close(portal);
2978 if (search_values_count) pfree(search_values);
2981 for (i = 0; i < covcount; i++) {
2982 covvcnts[i].
percent = (double) covvcnts[i].count / covtotal;
2986 funcctx->user_fctx = covvcnts;
2989 funcctx->max_calls = covcount;
2992 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
2994 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2996 "function returning record called in context " 2997 "that cannot accept type record" 3002 BlessTupleDesc(tupdesc);
3003 funcctx->tuple_desc = tupdesc;
3005 MemoryContextSwitchTo(oldcontext);
3009 funcctx = SRF_PERCALL_SETUP();
3011 call_cntr = funcctx->call_cntr;
3012 max_calls = funcctx->max_calls;
3013 tupdesc = funcctx->tuple_desc;
3014 covvcnts2 = funcctx->user_fctx;
3017 if (call_cntr < max_calls) {
3018 int values_length = 3;
3019 Datum values[values_length];
3020 bool nulls[values_length];
3026 memset(nulls,
FALSE,
sizeof(
bool) * values_length);
3028 values[0] = Float8GetDatum(covvcnts2[call_cntr].
value);
3029 values[1] = UInt32GetDatum(covvcnts2[call_cntr].
count);
3030 values[2] = Float8GetDatum(covvcnts2[call_cntr].percent);
3033 tuple = heap_form_tuple(tupdesc, values, nulls);
3036 result = HeapTupleGetDatum(tuple);
3038 SRF_RETURN_NEXT(funcctx, result);
3043 SRF_RETURN_DONE(funcctx);
Datum RASTER_summaryStats(PG_FUNCTION_ARGS)
static rtpg_summarystats_arg rtpg_summarystats_arg_init()
int quantile_llist_destroy(struct quantile_llist **list, uint32_t list_count)
int rt_raster_get_num_bands(rt_raster raster)
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Datum RASTER_valueCount(PG_FUNCTION_ARGS)
void rt_band_destroy(rt_band band)
Destroy a raster band.
rt_quantile rt_band_get_quantiles_stream(rt_band band, int exclude_nodata_value, double sample, uint64_t cov_count, struct quantile_llist **qlls, uint32_t *qlls_count, double *quantiles, int quantiles_count, uint32_t *rtn_count)
Compute the default set of or requested quantiles for a coverage.
struct rtpg_summarystats_arg_t * rtpg_summarystats_arg
#define POSTGIS_RT_DEBUGF(level, msg,...)
Datum RASTER_summaryStats_transfn(PG_FUNCTION_ARGS)
Datum RASTER_histogramCoverage(PG_FUNCTION_ARGS)
rt_quantile rt_band_get_quantiles(rt_bandstats stats, double *quantiles, int quantiles_count, uint32_t *rtn_count)
Compute the default set of or requested quantiles for a set of data the quantile formula used is same...
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
PG_FUNCTION_INFO_V1(RASTER_summaryStats)
Get summary stats of a band.
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
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
bool exclude_nodata_value
struct rt_valuecount_t * rt_valuecount
struct rt_bandstats_t * rt_bandstats
rt_valuecount rt_band_get_value_count(rt_band band, int exclude_nodata_value, double *search_values, uint32_t search_values_count, double roundto, uint32_t *rtn_total, uint32_t *rtn_count)
Count the number of times provided value(s) occur in the band.
Datum RASTER_summaryStats_finalfn(PG_FUNCTION_ARGS)
Datum RASTER_valueCountCoverage(PG_FUNCTION_ARGS)
static void rtpg_summarystats_arg_destroy(rtpg_summarystats_arg arg)
Datum RASTER_histogram(PG_FUNCTION_ARGS)
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.
Datum RASTER_quantile(PG_FUNCTION_ARGS)
Datum RASTER_quantileCoverage(PG_FUNCTION_ARGS)
#define POSTGIS_RT_DEBUG(level, msg)
Datum RASTER_summaryStatsCoverage(PG_FUNCTION_ARGS)
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.