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"
43 #include "access/htup_details.h"
67 #define VALUES_LENGTH 6
78 int32_t bandindex = 1;
79 bool exclude_nodata_value =
TRUE;
93 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
97 PG_FREE_IF_COPY(pgraster, 0);
98 elog(ERROR,
"RASTER_summaryStats: Cannot deserialize raster");
103 if (!PG_ARGISNULL(1))
104 bandindex = PG_GETARG_INT32(1);
106 if (bandindex < 1 || bandindex > num_bands) {
107 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
109 PG_FREE_IF_COPY(pgraster, 0);
114 if (!PG_ARGISNULL(2))
115 exclude_nodata_value = PG_GETARG_BOOL(2);
118 if (!PG_ARGISNULL(3)) {
119 sample = PG_GETARG_FLOAT8(3);
120 if (sample < 0 || sample > 1) {
121 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
123 PG_FREE_IF_COPY(pgraster, 0);
126 else if (
FLT_EQ(sample, 0.0))
135 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
137 PG_FREE_IF_COPY(pgraster, 0);
145 PG_FREE_IF_COPY(pgraster, 0);
147 elog(NOTICE,
"Cannot compute summary statistics for band at index %d. Returning NULL", bandindex);
152 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
154 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
156 "function returning record called in context "
157 "that cannot accept type record"
162 BlessTupleDesc(tupdesc);
166 values[0] = Int64GetDatum(stats->
count);
167 if (stats->
count > 0) {
168 values[1] = Float8GetDatum(stats->
sum);
169 values[2] = Float8GetDatum(stats->
mean);
170 values[3] = Float8GetDatum(stats->
stddev);
171 values[4] = Float8GetDatum(stats->
min);
172 values[5] = Float8GetDatum(stats->
max);
183 tuple = heap_form_tuple(tupdesc, values, nulls);
186 result = HeapTupleGetDatum(tuple);
191 PG_RETURN_DATUM(result);
200 text *tablenametext = NULL;
201 char *tablename = NULL;
202 text *colnametext = NULL;
203 char *colname = NULL;
204 int32_t bandindex = 1;
205 bool exclude_nodata_value =
TRUE;
213 SPITupleTable *tuptable = NULL;
233 if (PG_ARGISNULL(0)) {
234 elog(NOTICE,
"Table name must be provided");
237 tablenametext = PG_GETARG_TEXT_P(0);
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);
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 tuple = SPI_tuptable->vals[0];
314 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
315 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
316 SPI_freetuptable(SPI_tuptable);
317 SPI_cursor_close(portal);
320 if (NULL != rtn) pfree(rtn);
321 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot get raster of coverage");
325 SPI_cursor_fetch(portal,
TRUE, 1);
329 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
333 SPI_freetuptable(SPI_tuptable);
334 SPI_cursor_close(portal);
337 if (NULL != rtn) pfree(rtn);
338 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot deserialize raster");
344 if (bandindex < 1 || bandindex > num_bands) {
345 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
349 SPI_freetuptable(SPI_tuptable);
350 SPI_cursor_close(portal);
353 if (NULL != rtn) pfree(rtn);
360 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
364 SPI_freetuptable(SPI_tuptable);
365 SPI_cursor_close(portal);
368 if (NULL != rtn) pfree(rtn);
379 elog(NOTICE,
"Cannot compute summary statistics for band at index %d. Returning NULL", bandindex);
381 SPI_freetuptable(SPI_tuptable);
382 SPI_cursor_close(portal);
385 if (NULL != rtn) pfree(rtn);
390 if (stats->
count > 0) {
394 SPI_freetuptable(SPI_tuptable);
395 SPI_cursor_close(portal);
398 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot allocate memory for summary stats of coverage");
417 if (stats->
min < rtn->
min)
419 if (stats->
max > rtn->
max)
427 SPI_cursor_fetch(portal,
TRUE, 1);
430 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
431 SPI_cursor_close(portal);
435 elog(ERROR,
"RASTER_summaryStatsCoverage: Cannot compute coverage summary stats");
449 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
451 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
453 "function returning record called in context "
454 "that cannot accept type record"
459 BlessTupleDesc(tupdesc);
463 values[0] = Int64GetDatum(rtn->
count);
464 if (rtn->
count > 0) {
465 values[1] = Float8GetDatum(rtn->
sum);
466 values[2] = Float8GetDatum(rtn->
mean);
467 values[3] = Float8GetDatum(rtn->
stddev);
468 values[4] = Float8GetDatum(rtn->
min);
469 values[5] = Float8GetDatum(rtn->
max);
480 tuple = heap_form_tuple(tupdesc, values, nulls);
483 result = HeapTupleGetDatum(tuple);
488 PG_RETURN_DATUM(result);
511 if (arg->
stats != NULL)
525 "rtpg_summarystats_arg_init: Cannot allocate memory for function arguments"
531 if (arg->
stats == NULL) {
535 "rtpg_summarystats_arg_init: Cannot allocate memory for stats function argument"
564 MemoryContext aggcontext;
565 MemoryContext oldcontext;
567 bool skiparg =
FALSE;
580 if (!AggCheckCallContext(fcinfo, &aggcontext)) {
583 "RASTER_summaryStats_transfn: Cannot be called in a non-aggregate context"
589 oldcontext = MemoryContextSwitchTo(aggcontext);
591 if (PG_ARGISNULL(0)) {
596 MemoryContextSwitchTo(oldcontext);
599 "RASTER_summaryStats_transfn: Cannot allocate memory for state variable"
613 if (!PG_ARGISNULL(1)) {
615 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
622 PG_FREE_IF_COPY(pgraster, 1);
624 MemoryContextSwitchTo(oldcontext);
625 elog(ERROR,
"RASTER_summaryStats_transfn: Cannot deserialize raster");
641 for (i = 2; i < nargs; i++) {
645 calltype = get_fn_expr_argtype(fcinfo->flinfo, i);
649 (calltype == INT2OID || calltype == INT4OID) &&
652 if (calltype == INT2OID)
663 PG_FREE_IF_COPY(pgraster, 1);
666 MemoryContextSwitchTo(oldcontext);
669 "RASTER_summaryStats_transfn: Invalid band index (must use 1-based). Returning NULL"
676 calltype == BOOLOID && (
684 (calltype == FLOAT4OID || calltype == FLOAT8OID) &&
687 if (calltype == FLOAT4OID)
688 state->
sample = PG_GETARG_FLOAT4(i);
690 state->
sample = PG_GETARG_FLOAT8(i);
698 PG_FREE_IF_COPY(pgraster, 1);
701 MemoryContextSwitchTo(oldcontext);
704 "Invalid sample percentage (must be between 0 and 1). Returning NULL"
717 PG_FREE_IF_COPY(pgraster, 1);
720 MemoryContextSwitchTo(oldcontext);
723 "RASTER_summaryStats_transfn: Unknown function parameter at index %d",
733 if (PG_ARGISNULL(1)) {
735 MemoryContextSwitchTo(oldcontext);
736 PG_RETURN_POINTER(state);
744 "Raster does not have band at index %d. Skipping raster",
749 PG_FREE_IF_COPY(pgraster, 1);
751 MemoryContextSwitchTo(oldcontext);
752 PG_RETURN_POINTER(state);
759 NOTICE,
"Cannot find band at index %d. Skipping raster",
764 PG_FREE_IF_COPY(pgraster, 1);
766 MemoryContextSwitchTo(oldcontext);
767 PG_RETURN_POINTER(state);
774 &(state->
cK), &(state->
cM), &(state->
cQ)
779 PG_FREE_IF_COPY(pgraster, 1);
784 "Cannot compute summary statistics for band at index %d. Returning NULL",
790 MemoryContextSwitchTo(oldcontext);
794 if (stats->
count > 0) {
818 MemoryContextSwitchTo(oldcontext);
822 PG_RETURN_POINTER(state);
839 if (!AggCheckCallContext(fcinfo, NULL)) {
840 elog(ERROR,
"RASTER_summaryStats_finalfn: Cannot be called in a non-aggregate context");
851 elog(ERROR,
"RASTER_summaryStats_finalfn: Cannot compute coverage summary stats");
867 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
870 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
872 "function returning record called in context "
873 "that cannot accept type record"
878 BlessTupleDesc(tupdesc);
882 values[0] = Int64GetDatum(state->
stats->
count);
884 values[1] = Float8GetDatum(state->
stats->
sum);
885 values[2] = Float8GetDatum(state->
stats->
mean);
887 values[4] = Float8GetDatum(state->
stats->
min);
888 values[5] = Float8GetDatum(state->
stats->
max);
899 tuple = heap_form_tuple(tupdesc, values, nulls);
902 result = HeapTupleGetDatum(tuple);
911 PG_RETURN_DATUM(result);
915 #define VALUES_LENGTH 4
923 FuncCallContext *funcctx;
933 if (SRF_IS_FIRSTCALL()) {
934 MemoryContext oldcontext;
939 int32_t bandindex = 1;
941 bool exclude_nodata_value =
TRUE;
943 uint32_t bin_count = 0;
944 double *bin_width = NULL;
945 uint32_t bin_width_count = 0;
967 funcctx = SRF_FIRSTCALL_INIT();
970 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
973 if (PG_ARGISNULL(0)) {
974 MemoryContextSwitchTo(oldcontext);
975 SRF_RETURN_DONE(funcctx);
977 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
981 PG_FREE_IF_COPY(pgraster, 0);
982 MemoryContextSwitchTo(oldcontext);
983 elog(ERROR,
"RASTER_histogram: Cannot deserialize raster");
984 SRF_RETURN_DONE(funcctx);
988 if (!PG_ARGISNULL(1))
989 bandindex = PG_GETARG_INT32(1);
991 if (bandindex < 1 || bandindex > num_bands) {
992 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
994 PG_FREE_IF_COPY(pgraster, 0);
995 MemoryContextSwitchTo(oldcontext);
996 SRF_RETURN_DONE(funcctx);
1000 if (!PG_ARGISNULL(2))
1001 exclude_nodata_value = PG_GETARG_BOOL(2);
1004 if (!PG_ARGISNULL(3)) {
1005 sample = PG_GETARG_FLOAT8(3);
1006 if (sample < 0 || sample > 1) {
1007 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
1009 PG_FREE_IF_COPY(pgraster, 0);
1010 MemoryContextSwitchTo(oldcontext);
1011 SRF_RETURN_DONE(funcctx);
1013 else if (
FLT_EQ(sample, 0.0))
1020 if (!PG_ARGISNULL(4)) {
1021 bin_count = PG_GETARG_INT32(4);
1022 if (bin_count < 1) bin_count = 0;
1026 if (!PG_ARGISNULL(5)) {
1027 array = PG_GETARG_ARRAYTYPE_P(5);
1028 etype = ARR_ELEMTYPE(array);
1029 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1037 PG_FREE_IF_COPY(pgraster, 0);
1038 MemoryContextSwitchTo(oldcontext);
1039 elog(ERROR,
"RASTER_histogram: Invalid data type for width");
1040 SRF_RETURN_DONE(funcctx);
1044 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1047 bin_width = palloc(
sizeof(
double) * n);
1048 for (i = 0, j = 0; i < n; i++) {
1049 if (nulls[i])
continue;
1053 width = (double) DatumGetFloat4(e[i]);
1056 width = (double) DatumGetFloat8(e[i]);
1060 if (width < 0 ||
FLT_EQ(width, 0.0)) {
1061 elog(NOTICE,
"Invalid value for width (must be greater than 0). Returning NULL");
1064 PG_FREE_IF_COPY(pgraster, 0);
1065 MemoryContextSwitchTo(oldcontext);
1066 SRF_RETURN_DONE(funcctx);
1069 bin_width[j] = width;
1073 bin_width_count = j;
1082 if (!PG_ARGISNULL(6))
1083 right = PG_GETARG_BOOL(6);
1086 if (!PG_ARGISNULL(7)) min = PG_GETARG_FLOAT8(7);
1089 if (!PG_ARGISNULL(8)) max = PG_GETARG_FLOAT8(8);
1094 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
1096 PG_FREE_IF_COPY(pgraster, 0);
1097 MemoryContextSwitchTo(oldcontext);
1098 SRF_RETURN_DONE(funcctx);
1105 PG_FREE_IF_COPY(pgraster, 0);
1106 if (NULL == stats || NULL == stats->
values) {
1107 elog(NOTICE,
"Cannot compute summary statistics for band at index %d", bandindex);
1108 MemoryContextSwitchTo(oldcontext);
1109 SRF_RETURN_DONE(funcctx);
1111 else if (stats->
count < 1) {
1112 elog(NOTICE,
"Cannot compute histogram for band at index %d as the band has no values", bandindex);
1113 MemoryContextSwitchTo(oldcontext);
1114 SRF_RETURN_DONE(funcctx);
1119 if (bin_width_count) pfree(bin_width);
1121 if (NULL == hist || !
count) {
1122 elog(NOTICE,
"Cannot compute histogram for band at index %d", bandindex);
1123 MemoryContextSwitchTo(oldcontext);
1124 SRF_RETURN_DONE(funcctx);
1130 funcctx->user_fctx = hist;
1133 funcctx->max_calls =
count;
1136 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
1138 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1140 "function returning record called in context "
1141 "that cannot accept type record"
1146 BlessTupleDesc(tupdesc);
1147 funcctx->tuple_desc = tupdesc;
1149 MemoryContextSwitchTo(oldcontext);
1153 funcctx = SRF_PERCALL_SETUP();
1155 call_cntr = funcctx->call_cntr;
1156 max_calls = funcctx->max_calls;
1157 tupdesc = funcctx->tuple_desc;
1158 hist2 = funcctx->user_fctx;
1161 if (call_cntr < max_calls) {
1171 values[0] = Float8GetDatum(hist2[call_cntr].min);
1172 values[1] = Float8GetDatum(hist2[call_cntr].max);
1173 values[2] = Int64GetDatum(hist2[call_cntr].
count);
1174 values[3] = Float8GetDatum(hist2[call_cntr].percent);
1177 tuple = heap_form_tuple(tupdesc, values, nulls);
1180 result = HeapTupleGetDatum(tuple);
1182 SRF_RETURN_NEXT(funcctx, result);
1187 SRF_RETURN_DONE(funcctx);
1197 FuncCallContext *funcctx;
1209 if (SRF_IS_FIRSTCALL()) {
1210 MemoryContext oldcontext;
1212 text *tablenametext = NULL;
1213 char *tablename = NULL;
1214 text *colnametext = NULL;
1215 char *colname = NULL;
1216 int32_t bandindex = 1;
1217 bool exclude_nodata_value =
TRUE;
1219 uint32_t bin_count = 0;
1220 double *bin_width = NULL;
1221 uint32_t bin_width_count = 0;
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);
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);
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 < (uint32_t) 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(SPI_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(SPI_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 tuple = SPI_tuptable->vals[0];
1424 tmp = SPI_getvalue(tuple, tupdesc, 1);
1425 if (NULL == tmp || !strlen(tmp)) {
1427 SPI_freetuptable(SPI_tuptable);
1430 if (bin_width_count) pfree(bin_width);
1432 MemoryContextSwitchTo(oldcontext);
1433 elog(ERROR,
"RASTER_histogramCoverage: Cannot get summary stats of coverage");
1434 SRF_RETURN_DONE(funcctx);
1436 min = strtod(tmp, NULL);
1440 tmp = SPI_getvalue(tuple, tupdesc, 2);
1441 if (NULL == tmp || !strlen(tmp)) {
1443 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1446 if (bin_width_count) pfree(bin_width);
1448 MemoryContextSwitchTo(oldcontext);
1449 elog(ERROR,
"RASTER_histogramCoverage: Cannot get summary stats of coverage");
1450 SRF_RETURN_DONE(funcctx);
1452 max = strtod(tmp, NULL);
1458 len =
sizeof(char) * (strlen(
"SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
1459 sql = (
char *) palloc(len);
1462 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1465 if (bin_width_count) pfree(bin_width);
1467 MemoryContextSwitchTo(oldcontext);
1468 elog(ERROR,
"RASTER_histogramCoverage: Cannot allocate memory for sql");
1469 SRF_RETURN_DONE(funcctx);
1473 snprintf(
sql, len,
"SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
1475 portal = SPI_cursor_open_with_args(
1485 SPI_cursor_fetch(portal,
TRUE, 1);
1486 while (SPI_processed == 1 && SPI_tuptable != NULL) {
1487 tupdesc = SPI_tuptable->tupdesc;
1488 tuple = SPI_tuptable->vals[0];
1490 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
1491 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
1492 SPI_freetuptable(SPI_tuptable);
1493 SPI_cursor_close(portal);
1496 if (NULL != covhist) pfree(covhist);
1497 if (bin_width_count) pfree(bin_width);
1499 MemoryContextSwitchTo(oldcontext);
1500 elog(ERROR,
"RASTER_histogramCoverage: Cannot get raster of coverage");
1501 SRF_RETURN_DONE(funcctx);
1504 SPI_cursor_fetch(portal,
TRUE, 1);
1508 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
1513 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1514 SPI_cursor_close(portal);
1517 if (NULL != covhist) pfree(covhist);
1518 if (bin_width_count) pfree(bin_width);
1520 MemoryContextSwitchTo(oldcontext);
1521 elog(ERROR,
"RASTER_histogramCoverage: Cannot deserialize raster");
1522 SRF_RETURN_DONE(funcctx);
1527 if (bandindex < 1 || bandindex > num_bands) {
1528 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
1532 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1533 SPI_cursor_close(portal);
1536 if (NULL != covhist) pfree(covhist);
1537 if (bin_width_count) pfree(bin_width);
1539 MemoryContextSwitchTo(oldcontext);
1540 SRF_RETURN_DONE(funcctx);
1546 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
1550 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1551 SPI_cursor_close(portal);
1554 if (NULL != covhist) pfree(covhist);
1555 if (bin_width_count) pfree(bin_width);
1557 MemoryContextSwitchTo(oldcontext);
1558 SRF_RETURN_DONE(funcctx);
1567 if (NULL == stats) {
1568 elog(NOTICE,
"Cannot compute summary statistics for band at index %d. Returning NULL", bandindex);
1570 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1571 SPI_cursor_close(portal);
1574 if (NULL != covhist) pfree(covhist);
1575 if (bin_width_count) pfree(bin_width);
1577 MemoryContextSwitchTo(oldcontext);
1578 SRF_RETURN_DONE(funcctx);
1582 if (stats->
count > 0) {
1585 if (NULL == hist || !
count) {
1586 elog(NOTICE,
"Cannot compute histogram for band at index %d", bandindex);
1588 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1589 SPI_cursor_close(portal);
1592 if (NULL != covhist) pfree(covhist);
1593 if (bin_width_count) pfree(bin_width);
1595 MemoryContextSwitchTo(oldcontext);
1596 SRF_RETURN_DONE(funcctx);
1602 if (NULL == covhist) {
1604 if (NULL == covhist) {
1607 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1608 SPI_cursor_close(portal);
1611 if (bin_width_count) pfree(bin_width);
1613 MemoryContextSwitchTo(oldcontext);
1614 elog(ERROR,
"RASTER_histogramCoverage: Cannot allocate memory for histogram of coverage");
1615 SRF_RETURN_DONE(funcctx);
1618 for (i = 0; i <
count; i++) {
1619 sum += hist[i].
count;
1622 covhist[i].
min = hist[i].
min;
1623 covhist[i].
max = hist[i].
max;
1627 for (i = 0; i <
count; i++) {
1628 sum += hist[i].
count;
1636 if (bin_count <= 0) bin_count =
count;
1640 SPI_cursor_fetch(portal,
TRUE, 1);
1643 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
1644 SPI_cursor_close(portal);
1647 if (bin_width_count) pfree(bin_width);
1651 for (i = 0; i <
count; i++)
1652 covhist[i].percent = covhist[i].
count / (
double) sum;
1656 funcctx->user_fctx = covhist;
1659 funcctx->max_calls =
count;
1662 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
1664 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1666 "function returning record called in context "
1667 "that cannot accept type record"
1672 BlessTupleDesc(tupdesc);
1673 funcctx->tuple_desc = tupdesc;
1675 MemoryContextSwitchTo(oldcontext);
1679 funcctx = SRF_PERCALL_SETUP();
1681 call_cntr = funcctx->call_cntr;
1682 max_calls = funcctx->max_calls;
1683 tupdesc = funcctx->tuple_desc;
1684 covhist2 = funcctx->user_fctx;
1687 if (call_cntr < max_calls) {
1697 values[0] = Float8GetDatum(covhist2[call_cntr].min);
1698 values[1] = Float8GetDatum(covhist2[call_cntr].max);
1699 values[2] = Int64GetDatum(covhist2[call_cntr].
count);
1700 values[3] = Float8GetDatum(covhist2[call_cntr].percent);
1703 tuple = heap_form_tuple(tupdesc, values, nulls);
1706 result = HeapTupleGetDatum(tuple);
1708 SRF_RETURN_NEXT(funcctx, result);
1713 SRF_RETURN_DONE(funcctx);
1717 #undef VALUES_LENGTH
1718 #define VALUES_LENGTH 2
1726 FuncCallContext *funcctx;
1736 if (SRF_IS_FIRSTCALL()) {
1737 MemoryContext oldcontext;
1742 int32_t bandindex = 0;
1744 bool exclude_nodata_value =
TRUE;
1746 double *quantiles = NULL;
1747 uint32_t quantiles_count = 0;
1748 double quantile = 0;
1764 funcctx = SRF_FIRSTCALL_INIT();
1767 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1770 if (PG_ARGISNULL(0)) {
1771 MemoryContextSwitchTo(oldcontext);
1772 SRF_RETURN_DONE(funcctx);
1774 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1778 PG_FREE_IF_COPY(pgraster, 0);
1779 MemoryContextSwitchTo(oldcontext);
1780 elog(ERROR,
"RASTER_quantile: Cannot deserialize raster");
1781 SRF_RETURN_DONE(funcctx);
1785 bandindex = PG_GETARG_INT32(1);
1787 if (bandindex < 1 || bandindex > num_bands) {
1788 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
1790 PG_FREE_IF_COPY(pgraster, 0);
1791 MemoryContextSwitchTo(oldcontext);
1792 SRF_RETURN_DONE(funcctx);
1796 if (!PG_ARGISNULL(2))
1797 exclude_nodata_value = PG_GETARG_BOOL(2);
1800 if (!PG_ARGISNULL(3)) {
1801 sample = PG_GETARG_FLOAT8(3);
1802 if (sample < 0 || sample > 1) {
1803 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
1805 PG_FREE_IF_COPY(pgraster, 0);
1806 MemoryContextSwitchTo(oldcontext);
1807 SRF_RETURN_DONE(funcctx);
1809 else if (
FLT_EQ(sample, 0.0))
1816 if (!PG_ARGISNULL(4)) {
1817 array = PG_GETARG_ARRAYTYPE_P(4);
1818 etype = ARR_ELEMTYPE(array);
1819 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
1827 PG_FREE_IF_COPY(pgraster, 0);
1828 MemoryContextSwitchTo(oldcontext);
1829 elog(ERROR,
"RASTER_quantile: Invalid data type for quantiles");
1830 SRF_RETURN_DONE(funcctx);
1834 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
1837 quantiles = palloc(
sizeof(
double) * n);
1838 for (i = 0, j = 0; i < n; i++) {
1839 if (nulls[i])
continue;
1843 quantile = (double) DatumGetFloat4(e[i]);
1846 quantile = (double) DatumGetFloat8(e[i]);
1850 if (quantile < 0 || quantile > 1) {
1851 elog(NOTICE,
"Invalid value for quantile (must be between 0 and 1). Returning NULL");
1854 PG_FREE_IF_COPY(pgraster, 0);
1855 MemoryContextSwitchTo(oldcontext);
1856 SRF_RETURN_DONE(funcctx);
1859 quantiles[j] = quantile;
1863 quantiles_count = j;
1874 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
1876 PG_FREE_IF_COPY(pgraster, 0);
1877 MemoryContextSwitchTo(oldcontext);
1878 SRF_RETURN_DONE(funcctx);
1885 PG_FREE_IF_COPY(pgraster, 0);
1886 if (NULL == stats || NULL == stats->
values) {
1887 elog(NOTICE,
"Cannot retrieve summary statistics for band at index %d", bandindex);
1888 MemoryContextSwitchTo(oldcontext);
1889 SRF_RETURN_DONE(funcctx);
1891 else if (stats->
count < 1) {
1892 elog(NOTICE,
"Cannot compute quantiles for band at index %d as the band has no values", bandindex);
1893 MemoryContextSwitchTo(oldcontext);
1894 SRF_RETURN_DONE(funcctx);
1899 if (quantiles_count) pfree(quantiles);
1901 if (NULL == quant || !
count) {
1902 elog(NOTICE,
"Cannot compute quantiles for band at index %d", bandindex);
1903 MemoryContextSwitchTo(oldcontext);
1904 SRF_RETURN_DONE(funcctx);
1910 funcctx->user_fctx = quant;
1913 funcctx->max_calls =
count;
1916 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
1918 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1920 "function returning record called in context "
1921 "that cannot accept type record"
1926 BlessTupleDesc(tupdesc);
1927 funcctx->tuple_desc = tupdesc;
1929 MemoryContextSwitchTo(oldcontext);
1933 funcctx = SRF_PERCALL_SETUP();
1935 call_cntr = funcctx->call_cntr;
1936 max_calls = funcctx->max_calls;
1937 tupdesc = funcctx->tuple_desc;
1938 quant2 = funcctx->user_fctx;
1941 if (call_cntr < max_calls) {
1951 values[0] = Float8GetDatum(quant2[call_cntr].quantile);
1952 values[1] = Float8GetDatum(quant2[call_cntr].
value);
1955 tuple = heap_form_tuple(tupdesc, values, nulls);
1958 result = HeapTupleGetDatum(tuple);
1960 SRF_RETURN_NEXT(funcctx, result);
1965 SRF_RETURN_DONE(funcctx);
1975 FuncCallContext *funcctx;
1987 if (SRF_IS_FIRSTCALL()) {
1988 MemoryContext oldcontext;
1990 text *tablenametext = NULL;
1991 char *tablename = NULL;
1992 text *colnametext = NULL;
1993 char *colname = NULL;
1994 int32_t bandindex = 1;
1995 bool exclude_nodata_value =
TRUE;
1997 double *quantiles = NULL;
1998 uint32_t quantiles_count = 0;
1999 double quantile = 0;
2005 uint64_t cov_count = 0;
2008 SPITupleTable *tuptable = NULL;
2011 bool isNull =
FALSE;
2018 uint32_t qlls_count;
2034 funcctx = SRF_FIRSTCALL_INIT();
2037 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2040 if (PG_ARGISNULL(0)) {
2041 elog(NOTICE,
"Table name must be provided");
2042 MemoryContextSwitchTo(oldcontext);
2043 SRF_RETURN_DONE(funcctx);
2045 tablenametext = PG_GETARG_TEXT_P(0);
2047 if (!strlen(tablename)) {
2048 elog(NOTICE,
"Table name must be provided");
2049 MemoryContextSwitchTo(oldcontext);
2050 SRF_RETURN_DONE(funcctx);
2055 if (PG_ARGISNULL(1)) {
2056 elog(NOTICE,
"Column name must be provided");
2057 MemoryContextSwitchTo(oldcontext);
2058 SRF_RETURN_DONE(funcctx);
2060 colnametext = PG_GETARG_TEXT_P(1);
2062 if (!strlen(colname)) {
2063 elog(NOTICE,
"Column name must be provided");
2064 MemoryContextSwitchTo(oldcontext);
2065 SRF_RETURN_DONE(funcctx);
2070 if (!PG_ARGISNULL(2))
2071 bandindex = PG_GETARG_INT32(2);
2074 if (!PG_ARGISNULL(3))
2075 exclude_nodata_value = PG_GETARG_BOOL(3);
2078 if (!PG_ARGISNULL(4)) {
2079 sample = PG_GETARG_FLOAT8(4);
2080 if (sample < 0 || sample > 1) {
2081 elog(NOTICE,
"Invalid sample percentage (must be between 0 and 1). Returning NULL");
2082 MemoryContextSwitchTo(oldcontext);
2083 SRF_RETURN_DONE(funcctx);
2085 else if (
FLT_EQ(sample, 0.0))
2092 if (!PG_ARGISNULL(5)) {
2093 array = PG_GETARG_ARRAYTYPE_P(5);
2094 etype = ARR_ELEMTYPE(array);
2095 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2102 MemoryContextSwitchTo(oldcontext);
2103 elog(ERROR,
"RASTER_quantileCoverage: Invalid data type for quantiles");
2104 SRF_RETURN_DONE(funcctx);
2108 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
2111 quantiles = palloc(
sizeof(
double) * n);
2112 for (i = 0, j = 0; i < (uint32_t) n; i++) {
2113 if (nulls[i])
continue;
2117 quantile = (double) DatumGetFloat4(e[i]);
2120 quantile = (double) DatumGetFloat8(e[i]);
2124 if (quantile < 0 || quantile > 1) {
2125 elog(NOTICE,
"Invalid value for quantile (must be between 0 and 1). Returning NULL");
2127 MemoryContextSwitchTo(oldcontext);
2128 SRF_RETURN_DONE(funcctx);
2135 quantiles_count = j;
2145 spi_result = SPI_connect();
2146 if (spi_result != SPI_OK_CONNECT) {
2147 MemoryContextSwitchTo(oldcontext);
2148 elog(ERROR,
"RASTER_quantileCoverage: Cannot connect to database using SPI");
2149 SRF_RETURN_DONE(funcctx);
2152 len =
sizeof(char) * (strlen(
"SELECT count FROM _st_summarystats('','',,::boolean,)") + strlen(tablename) + strlen(colname) + (
MAX_INT_CHARLEN * 2) +
MAX_DBL_CHARLEN + 1);
2153 sql = (
char *) palloc(len);
2156 if (SPI_tuptable) SPI_freetuptable(tuptable);
2159 MemoryContextSwitchTo(oldcontext);
2160 elog(ERROR,
"RASTER_quantileCoverage: Cannot allocate memory for sql");
2161 SRF_RETURN_DONE(funcctx);
2165 snprintf(
sql, len,
"SELECT count FROM _st_summarystats('%s','%s',%d,%d::boolean,%f)", tablename, colname, bandindex, (exclude_nodata_value ? 1 : 0), sample);
2167 spi_result = SPI_execute(
sql,
TRUE, 0);
2169 if (spi_result != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
2171 if (SPI_tuptable) SPI_freetuptable(tuptable);
2174 MemoryContextSwitchTo(oldcontext);
2175 elog(ERROR,
"RASTER_quantileCoverage: Cannot get summary stats of coverage");
2176 SRF_RETURN_DONE(funcctx);
2179 tupdesc = SPI_tuptable->tupdesc;
2180 tuptable = SPI_tuptable;
2181 tuple = tuptable->vals[0];
2183 tmp = SPI_getvalue(tuple, tupdesc, 1);
2184 if (NULL == tmp || !strlen(tmp)) {
2186 if (SPI_tuptable) SPI_freetuptable(tuptable);
2189 MemoryContextSwitchTo(oldcontext);
2190 elog(ERROR,
"RASTER_quantileCoverage: Cannot get summary stats of coverage");
2191 SRF_RETURN_DONE(funcctx);
2193 cov_count = strtol(tmp, NULL, 10);
2199 len =
sizeof(char) * (strlen(
"SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
2200 sql = (
char *) palloc(len);
2203 if (SPI_tuptable) SPI_freetuptable(tuptable);
2206 MemoryContextSwitchTo(oldcontext);
2207 elog(ERROR,
"RASTER_quantileCoverage: Cannot allocate memory for sql");
2208 SRF_RETURN_DONE(funcctx);
2212 snprintf(
sql, len,
"SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
2214 portal = SPI_cursor_open_with_args(
2224 SPI_cursor_fetch(portal,
TRUE, 1);
2225 while (SPI_processed == 1 && SPI_tuptable != NULL) {
2226 if (NULL != covquant) pfree(covquant);
2228 tupdesc = SPI_tuptable->tupdesc;
2229 tuple = SPI_tuptable->vals[0];
2231 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
2232 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
2233 SPI_freetuptable(SPI_tuptable);
2234 SPI_cursor_close(portal);
2237 MemoryContextSwitchTo(oldcontext);
2238 elog(ERROR,
"RASTER_quantileCoverage: Cannot get raster of coverage");
2239 SRF_RETURN_DONE(funcctx);
2242 SPI_cursor_fetch(portal,
TRUE, 1);
2246 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
2251 SPI_freetuptable(SPI_tuptable);
2252 SPI_cursor_close(portal);
2255 MemoryContextSwitchTo(oldcontext);
2256 elog(ERROR,
"RASTER_quantileCoverage: Cannot deserialize raster");
2257 SRF_RETURN_DONE(funcctx);
2262 if (bandindex < 1 || bandindex > num_bands) {
2263 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
2267 SPI_freetuptable(SPI_tuptable);
2268 SPI_cursor_close(portal);
2271 MemoryContextSwitchTo(oldcontext);
2272 SRF_RETURN_DONE(funcctx);
2278 elog(NOTICE,
"Cannot find raster band of index %d. Returning NULL", bandindex);
2282 SPI_freetuptable(SPI_tuptable);
2283 SPI_cursor_close(portal);
2286 MemoryContextSwitchTo(oldcontext);
2287 SRF_RETURN_DONE(funcctx);
2292 exclude_nodata_value, sample, cov_count,
2294 quantiles, quantiles_count,
2301 if (!covquant || !
count) {
2302 elog(NOTICE,
"Cannot compute quantiles for band at index %d", bandindex);
2304 SPI_freetuptable(SPI_tuptable);
2305 SPI_cursor_close(portal);
2308 MemoryContextSwitchTo(oldcontext);
2309 SRF_RETURN_DONE(funcctx);
2313 SPI_cursor_fetch(portal,
TRUE, 1);
2317 for (i = 0; i <
count; i++) {
2320 if (covquant2[i].has_value)
2327 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
2328 SPI_cursor_close(portal);
2331 if (quantiles_count) pfree(quantiles);
2336 funcctx->user_fctx = covquant2;
2339 funcctx->max_calls =
count;
2342 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
2344 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2346 "function returning record called in context "
2347 "that cannot accept type record"
2352 BlessTupleDesc(tupdesc);
2353 funcctx->tuple_desc = tupdesc;
2355 MemoryContextSwitchTo(oldcontext);
2359 funcctx = SRF_PERCALL_SETUP();
2361 call_cntr = funcctx->call_cntr;
2362 max_calls = funcctx->max_calls;
2363 tupdesc = funcctx->tuple_desc;
2364 covquant2 = funcctx->user_fctx;
2367 if (call_cntr < max_calls) {
2377 values[0] = Float8GetDatum(covquant2[call_cntr].
quantile);
2378 if (covquant2[call_cntr].has_value)
2379 values[1] = Float8GetDatum(covquant2[call_cntr].
value);
2384 tuple = heap_form_tuple(tupdesc, values, nulls);
2387 result = HeapTupleGetDatum(tuple);
2389 SRF_RETURN_NEXT(funcctx, result);
2395 SRF_RETURN_DONE(funcctx);
2399 #undef VALUES_LENGTH
2400 #define VALUES_LENGTH 3
2405 FuncCallContext *funcctx;
2415 if (SRF_IS_FIRSTCALL()) {
2416 MemoryContext oldcontext;
2421 int32_t bandindex = 0;
2423 bool exclude_nodata_value =
TRUE;
2424 double *search_values = NULL;
2425 uint32_t search_values_count = 0;
2441 funcctx = SRF_FIRSTCALL_INIT();
2444 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2447 if (PG_ARGISNULL(0)) {
2448 MemoryContextSwitchTo(oldcontext);
2449 SRF_RETURN_DONE(funcctx);
2451 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2455 PG_FREE_IF_COPY(pgraster, 0);
2456 MemoryContextSwitchTo(oldcontext);
2457 elog(ERROR,
"RASTER_valueCount: Cannot deserialize raster");
2458 SRF_RETURN_DONE(funcctx);
2462 bandindex = PG_GETARG_INT32(1);
2464 if (bandindex < 1 || bandindex > num_bands) {
2465 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
2467 PG_FREE_IF_COPY(pgraster, 0);
2468 MemoryContextSwitchTo(oldcontext);
2469 SRF_RETURN_DONE(funcctx);
2473 if (!PG_ARGISNULL(2))
2474 exclude_nodata_value = PG_GETARG_BOOL(2);
2477 if (!PG_ARGISNULL(3)) {
2478 array = PG_GETARG_ARRAYTYPE_P(3);
2479 etype = ARR_ELEMTYPE(array);
2480 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2488 PG_FREE_IF_COPY(pgraster, 0);
2489 MemoryContextSwitchTo(oldcontext);
2490 elog(ERROR,
"RASTER_valueCount: Invalid data type for values");
2491 SRF_RETURN_DONE(funcctx);
2495 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
2498 search_values = palloc(
sizeof(
double) * n);
2499 for (i = 0, j = 0; i < n; i++) {
2500 if (nulls[i])
continue;
2504 search_values[j] = (double) DatumGetFloat4(e[i]);
2507 search_values[j] = (double) DatumGetFloat8(e[i]);
2514 search_values_count = j;
2517 pfree(search_values);
2518 search_values = NULL;
2523 if (!PG_ARGISNULL(4)) {
2524 roundto = PG_GETARG_FLOAT8(4);
2525 if (roundto < 0.) roundto = 0;
2531 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
2533 PG_FREE_IF_COPY(pgraster, 0);
2534 MemoryContextSwitchTo(oldcontext);
2535 SRF_RETURN_DONE(funcctx);
2542 PG_FREE_IF_COPY(pgraster, 0);
2543 if (NULL == vcnts || !
count) {
2544 elog(NOTICE,
"Cannot count the values for band at index %d", bandindex);
2545 MemoryContextSwitchTo(oldcontext);
2546 SRF_RETURN_DONE(funcctx);
2552 funcctx->user_fctx = vcnts;
2555 funcctx->max_calls =
count;
2558 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
2560 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2562 "function returning record called in context "
2563 "that cannot accept type record"
2568 BlessTupleDesc(tupdesc);
2569 funcctx->tuple_desc = tupdesc;
2571 MemoryContextSwitchTo(oldcontext);
2575 funcctx = SRF_PERCALL_SETUP();
2577 call_cntr = funcctx->call_cntr;
2578 max_calls = funcctx->max_calls;
2579 tupdesc = funcctx->tuple_desc;
2580 vcnts2 = funcctx->user_fctx;
2583 if (call_cntr < max_calls) {
2593 values[0] = Float8GetDatum(vcnts2[call_cntr].
value);
2594 values[1] = UInt32GetDatum(vcnts2[call_cntr].
count);
2595 values[2] = Float8GetDatum(vcnts2[call_cntr].percent);
2598 tuple = heap_form_tuple(tupdesc, values, nulls);
2601 result = HeapTupleGetDatum(tuple);
2603 SRF_RETURN_NEXT(funcctx, result);
2608 SRF_RETURN_DONE(funcctx);
2615 FuncCallContext *funcctx;
2619 uint64_t covcount = 0;
2620 uint64_t covtotal = 0;
2629 if (SRF_IS_FIRSTCALL()) {
2630 MemoryContext oldcontext;
2632 text *tablenametext = NULL;
2633 char *tablename = NULL;
2634 text *colnametext = NULL;
2635 char *colname = NULL;
2636 int32_t bandindex = 1;
2637 bool exclude_nodata_value =
TRUE;
2638 double *search_values = NULL;
2639 uint32_t search_values_count = 0;
2648 bool isNull =
FALSE;
2670 funcctx = SRF_FIRSTCALL_INIT();
2673 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2676 if (PG_ARGISNULL(0)) {
2677 elog(NOTICE,
"Table name must be provided");
2678 MemoryContextSwitchTo(oldcontext);
2679 SRF_RETURN_DONE(funcctx);
2681 tablenametext = PG_GETARG_TEXT_P(0);
2683 if (!strlen(tablename)) {
2684 elog(NOTICE,
"Table name must be provided");
2685 MemoryContextSwitchTo(oldcontext);
2686 SRF_RETURN_DONE(funcctx);
2691 if (PG_ARGISNULL(1)) {
2692 elog(NOTICE,
"Column name must be provided");
2693 MemoryContextSwitchTo(oldcontext);
2694 SRF_RETURN_DONE(funcctx);
2696 colnametext = PG_GETARG_TEXT_P(1);
2698 if (!strlen(colname)) {
2699 elog(NOTICE,
"Column name must be provided");
2700 MemoryContextSwitchTo(oldcontext);
2701 SRF_RETURN_DONE(funcctx);
2706 if (!PG_ARGISNULL(2))
2707 bandindex = PG_GETARG_INT32(2);
2710 if (!PG_ARGISNULL(3))
2711 exclude_nodata_value = PG_GETARG_BOOL(3);
2714 if (!PG_ARGISNULL(4)) {
2715 array = PG_GETARG_ARRAYTYPE_P(4);
2716 etype = ARR_ELEMTYPE(array);
2717 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2724 MemoryContextSwitchTo(oldcontext);
2725 elog(ERROR,
"RASTER_valueCountCoverage: Invalid data type for values");
2726 SRF_RETURN_DONE(funcctx);
2730 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
2733 search_values = palloc(
sizeof(
double) * n);
2734 for (i = 0, j = 0; i < (uint32_t) n; i++) {
2735 if (nulls[i])
continue;
2739 search_values[j] = (double) DatumGetFloat4(e[i]);
2742 search_values[j] = (double) DatumGetFloat8(e[i]);
2749 search_values_count = j;
2752 pfree(search_values);
2753 search_values = NULL;
2758 if (!PG_ARGISNULL(5)) {
2759 roundto = PG_GETARG_FLOAT8(5);
2760 if (roundto < 0.) roundto = 0;
2765 spi_result = SPI_connect();
2766 if (spi_result != SPI_OK_CONNECT) {
2768 if (search_values_count) pfree(search_values);
2770 MemoryContextSwitchTo(oldcontext);
2771 elog(ERROR,
"RASTER_valueCountCoverage: Cannot connect to database using SPI");
2772 SRF_RETURN_DONE(funcctx);
2776 len =
sizeof(char) * (strlen(
"SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
2777 sql = (
char *) palloc(len);
2780 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
2783 if (search_values_count) pfree(search_values);
2785 MemoryContextSwitchTo(oldcontext);
2786 elog(ERROR,
"RASTER_valueCountCoverage: Cannot allocate memory for sql");
2787 SRF_RETURN_DONE(funcctx);
2791 snprintf(
sql, len,
"SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
2793 portal = SPI_cursor_open_with_args(
2803 SPI_cursor_fetch(portal,
TRUE, 1);
2804 while (SPI_processed == 1 && SPI_tuptable != NULL) {
2805 tupdesc = SPI_tuptable->tupdesc;
2806 tuple = SPI_tuptable->vals[0];
2808 datum = SPI_getbinval(tuple, tupdesc, 1, &isNull);
2809 if (SPI_result == SPI_ERROR_NOATTRIBUTE) {
2811 SPI_freetuptable(SPI_tuptable);
2812 SPI_cursor_close(portal);
2815 if (NULL != covvcnts) pfree(covvcnts);
2816 if (search_values_count) pfree(search_values);
2818 MemoryContextSwitchTo(oldcontext);
2819 elog(ERROR,
"RASTER_valueCountCoverage: Cannot get raster of coverage");
2820 SRF_RETURN_DONE(funcctx);
2823 SPI_cursor_fetch(portal,
TRUE, 1);
2827 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
2832 SPI_freetuptable(SPI_tuptable);
2833 SPI_cursor_close(portal);
2836 if (NULL != covvcnts) pfree(covvcnts);
2837 if (search_values_count) pfree(search_values);
2839 MemoryContextSwitchTo(oldcontext);
2840 elog(ERROR,
"RASTER_valueCountCoverage: Cannot deserialize raster");
2841 SRF_RETURN_DONE(funcctx);
2846 if (bandindex < 1 || bandindex > num_bands) {
2847 elog(NOTICE,
"Invalid band index (must use 1-based). Returning NULL");
2851 SPI_freetuptable(SPI_tuptable);
2852 SPI_cursor_close(portal);
2855 if (NULL != covvcnts) pfree(covvcnts);
2856 if (search_values_count) pfree(search_values);
2858 MemoryContextSwitchTo(oldcontext);
2859 SRF_RETURN_DONE(funcctx);
2865 elog(NOTICE,
"Cannot find band at index %d. Returning NULL", bandindex);
2869 SPI_freetuptable(SPI_tuptable);
2870 SPI_cursor_close(portal);
2873 if (NULL != covvcnts) pfree(covvcnts);
2874 if (search_values_count) pfree(search_values);
2876 MemoryContextSwitchTo(oldcontext);
2877 SRF_RETURN_DONE(funcctx);
2884 if (NULL == vcnts || !
count) {
2885 elog(NOTICE,
"Cannot count the values for band at index %d", bandindex);
2887 SPI_freetuptable(SPI_tuptable);
2888 SPI_cursor_close(portal);
2891 if (NULL != covvcnts)
free(covvcnts);
2892 if (search_values_count) pfree(search_values);
2894 MemoryContextSwitchTo(oldcontext);
2895 SRF_RETURN_DONE(funcctx);
2900 if (NULL == covvcnts) {
2902 if (NULL == covvcnts) {
2904 SPI_freetuptable(SPI_tuptable);
2905 SPI_cursor_close(portal);
2908 if (search_values_count) pfree(search_values);
2910 MemoryContextSwitchTo(oldcontext);
2911 elog(ERROR,
"RASTER_valueCountCoverage: Cannot allocate memory for value counts of coverage");
2912 SRF_RETURN_DONE(funcctx);
2915 for (i = 0; i <
count; i++) {
2924 for (i = 0; i <
count; i++) {
2927 for (j = 0; j < covcount; j++) {
2939 covvcnts = SPI_repalloc(covvcnts,
sizeof(
struct rt_valuecount_t) * covcount);
2941 SPI_freetuptable(SPI_tuptable);
2942 SPI_cursor_close(portal);
2945 if (search_values_count) pfree(search_values);
2947 MemoryContextSwitchTo(oldcontext);
2948 elog(ERROR,
"RASTER_valueCountCoverage: Cannot change allocated memory for value counts of coverage");
2949 SRF_RETURN_DONE(funcctx);
2952 covvcnts[covcount - 1].
value = vcnts[i].
value;
2953 covvcnts[covcount - 1].
count = vcnts[i].
count;
2954 covvcnts[covcount - 1].
percent = -1;
2964 SPI_cursor_fetch(portal,
TRUE, 1);
2967 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
2968 SPI_cursor_close(portal);
2971 if (search_values_count) pfree(search_values);
2974 for (i = 0; i < covcount; i++) {
2975 covvcnts[i].
percent = (double) covvcnts[i].
count / covtotal;
2979 funcctx->user_fctx = covvcnts;
2982 funcctx->max_calls = covcount;
2985 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
2987 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2989 "function returning record called in context "
2990 "that cannot accept type record"
2995 BlessTupleDesc(tupdesc);
2996 funcctx->tuple_desc = tupdesc;
2998 MemoryContextSwitchTo(oldcontext);
3002 funcctx = SRF_PERCALL_SETUP();
3004 call_cntr = funcctx->call_cntr;
3005 max_calls = funcctx->max_calls;
3006 tupdesc = funcctx->tuple_desc;
3007 covvcnts2 = funcctx->user_fctx;
3010 if (call_cntr < max_calls) {
3020 values[0] = Float8GetDatum(covvcnts2[call_cntr].
value);
3021 values[1] = UInt32GetDatum(covvcnts2[call_cntr].
count);
3022 values[2] = Float8GetDatum(covvcnts2[call_cntr].percent);
3025 tuple = heap_form_tuple(tupdesc, values, nulls);
3028 result = HeapTupleGetDatum(tuple);
3030 SRF_RETURN_NEXT(funcctx, result);
3035 SRF_RETURN_DONE(funcctx);
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
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, uint32_t quantiles_count, uint32_t *rtn_count)
Compute the default set of or requested quantiles for a coverage.
struct rt_bandstats_t * rt_bandstats
int quantile_llist_destroy(struct quantile_llist **list, uint32_t list_count)
void rt_band_destroy(rt_band band)
Destroy a raster band.
uint16_t rt_raster_get_num_bands(rt_raster raster)
struct rt_valuecount_t * rt_valuecount
rt_histogram rt_band_get_histogram(rt_bandstats stats, uint32_t bin_count, double *bin_widths, uint32_t bin_widths_count, int right, double min, double max, uint32_t *rtn_count)
Count the distribution of data.
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.
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_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
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
char * text_to_cstring(const text *textptr)
Datum RASTER_summaryStats(PG_FUNCTION_ARGS)
Datum RASTER_summaryStatsCoverage(PG_FUNCTION_ARGS)
struct rtpg_summarystats_arg_t * rtpg_summarystats_arg
Datum RASTER_histogram(PG_FUNCTION_ARGS)
static void rtpg_summarystats_arg_destroy(rtpg_summarystats_arg arg)
Datum RASTER_histogramCoverage(PG_FUNCTION_ARGS)
Datum RASTER_valueCountCoverage(PG_FUNCTION_ARGS)
Datum RASTER_valueCount(PG_FUNCTION_ARGS)
Datum RASTER_quantileCoverage(PG_FUNCTION_ARGS)
static rtpg_summarystats_arg rtpg_summarystats_arg_init()
Datum RASTER_summaryStats_transfn(PG_FUNCTION_ARGS)
Datum RASTER_quantile(PG_FUNCTION_ARGS)
Datum RASTER_summaryStats_finalfn(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(RASTER_summaryStats)
Get summary stats of a band.
#define POSTGIS_RT_DEBUG(level, msg)
#define POSTGIS_RT_DEBUGF(level, msg,...)
bool exclude_nodata_value