1974{
1975 FuncCallContext *funcctx;
1976 TupleDesc tupdesc;
1977
1978 uint32_t i;
1981 int call_cntr;
1982 int max_calls;
1983
1985
1986
1987 if (SRF_IS_FIRSTCALL()) {
1988 MemoryContext oldcontext;
1989
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;
1996 double sample = 0;
1997 double *quantiles = NULL;
1998 uint32_t quantiles_count = 0;
1999 double quantile = 0;
2001
2002 int len = 0;
2004 char *tmp = NULL;
2005 uint64_t cov_count = 0;
2006 int spi_result;
2007 Portal portal;
2008 SPITupleTable *tuptable = NULL;
2009 HeapTuple tuple;
2010 Datum datum;
2011 bool isNull =
FALSE;
2012
2016 int num_bands = 0;
2018 uint32_t qlls_count;
2019
2020 int j;
2021 int n;
2022
2023 ArrayType *array;
2024 Oid etype;
2025 Datum *e;
2026 bool *nulls;
2027 int16 typlen;
2028 bool typbyval;
2029 char typalign;
2030
2032
2033
2034 funcctx = SRF_FIRSTCALL_INIT();
2035
2036
2037 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2038
2039
2040 if (PG_ARGISNULL(0)) {
2041 elog(NOTICE, "Table name must be provided");
2042 MemoryContextSwitchTo(oldcontext);
2043 SRF_RETURN_DONE(funcctx);
2044 }
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);
2051 }
2053
2054
2055 if (PG_ARGISNULL(1)) {
2056 elog(NOTICE, "Column name must be provided");
2057 MemoryContextSwitchTo(oldcontext);
2058 SRF_RETURN_DONE(funcctx);
2059 }
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);
2066 }
2068
2069
2070 if (!PG_ARGISNULL(2))
2071 bandindex = PG_GETARG_INT32(2);
2072
2073
2074 if (!PG_ARGISNULL(3))
2075 exclude_nodata_value = PG_GETARG_BOOL(3);
2076
2077
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);
2084 }
2085 else if (
FLT_EQ(sample, 0.0))
2086 sample = 1;
2087 }
2088 else
2089 sample = 1;
2090
2091
2092 if (!PG_ARGISNULL(5)) {
2093 array = PG_GETARG_ARRAYTYPE_P(5);
2094 etype = ARR_ELEMTYPE(array);
2095 get_typlenbyvalalign(etype, &typlen, &typbyval, &typalign);
2096
2097 switch (etype) {
2098 case FLOAT4OID:
2099 case FLOAT8OID:
2100 break;
2101 default:
2102 MemoryContextSwitchTo(oldcontext);
2103 elog(ERROR, "RASTER_quantileCoverage: Invalid data type for quantiles");
2104 SRF_RETURN_DONE(funcctx);
2105 break;
2106 }
2107
2108 deconstruct_array(array, etype, typlen, typbyval, typalign, &e,
2109 &nulls, &n);
2110
2111 quantiles = palloc(sizeof(double) * n);
2112 for (i = 0, j = 0; i < (uint32_t) n; i++) {
2113 if (nulls[i]) continue;
2114
2115 switch (etype) {
2116 case FLOAT4OID:
2117 quantile = (double) DatumGetFloat4(e[i]);
2118 break;
2119 case FLOAT8OID:
2120 quantile = (double) DatumGetFloat8(e[i]);
2121 break;
2122 }
2123
2124 if (quantile < 0 || quantile > 1) {
2125 elog(NOTICE, "Invalid value for quantile (must be between 0 and 1). Returning NULL");
2126 pfree(quantiles);
2127 MemoryContextSwitchTo(oldcontext);
2128 SRF_RETURN_DONE(funcctx);
2129 }
2130
2133 j++;
2134 }
2135 quantiles_count = j;
2136
2137 if (j < 1) {
2138 pfree(quantiles);
2139 quantiles = NULL;
2140 }
2141 }
2142
2143
2144
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);
2150 }
2151
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);
2154 if (NULL == sql) {
2155
2156 if (SPI_tuptable) SPI_freetuptable(tuptable);
2157 SPI_finish();
2158
2159 MemoryContextSwitchTo(oldcontext);
2160 elog(ERROR, "RASTER_quantileCoverage: Cannot allocate memory for sql");
2161 SRF_RETURN_DONE(funcctx);
2162 }
2163
2164
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);
2168 pfree(sql);
2169 if (spi_result != SPI_OK_SELECT || SPI_tuptable == NULL || SPI_processed != 1) {
2170
2171 if (SPI_tuptable) SPI_freetuptable(tuptable);
2172 SPI_finish();
2173
2174 MemoryContextSwitchTo(oldcontext);
2175 elog(ERROR, "RASTER_quantileCoverage: Cannot get summary stats of coverage");
2176 SRF_RETURN_DONE(funcctx);
2177 }
2178
2179 tupdesc = SPI_tuptable->tupdesc;
2180 tuptable = SPI_tuptable;
2181 tuple = tuptable->vals[0];
2182
2183 tmp = SPI_getvalue(tuple, tupdesc, 1);
2184 if (NULL == tmp || !strlen(tmp)) {
2185
2186 if (SPI_tuptable) SPI_freetuptable(tuptable);
2187 SPI_finish();
2188
2189 MemoryContextSwitchTo(oldcontext);
2190 elog(ERROR, "RASTER_quantileCoverage: Cannot get summary stats of coverage");
2191 SRF_RETURN_DONE(funcctx);
2192 }
2193 cov_count = strtol(tmp, NULL, 10);
2195 pfree(tmp);
2196
2197
2198
2199 len = sizeof(char) * (strlen("SELECT \"\" FROM \"\" WHERE \"\" IS NOT NULL") + (strlen(colname) * 2) + strlen(tablename) + 1);
2200 sql = (
char *) palloc(len);
2201 if (NULL == sql) {
2202
2203 if (SPI_tuptable) SPI_freetuptable(tuptable);
2204 SPI_finish();
2205
2206 MemoryContextSwitchTo(oldcontext);
2207 elog(ERROR, "RASTER_quantileCoverage: Cannot allocate memory for sql");
2208 SRF_RETURN_DONE(funcctx);
2209 }
2210
2211
2212 snprintf(sql, len, "SELECT \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", colname, tablename, colname);
2214 portal = SPI_cursor_open_with_args(
2215 "coverage",
2216 sql,
2217 0, NULL,
2218 NULL, NULL,
2220 );
2221 pfree(sql);
2222
2223
2224 SPI_cursor_fetch(portal,
TRUE, 1);
2225 while (SPI_processed == 1 && SPI_tuptable != NULL) {
2226 if (NULL != covquant) pfree(covquant);
2227
2228 tupdesc = SPI_tuptable->tupdesc;
2229 tuple = SPI_tuptable->vals[0];
2230
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);
2235 SPI_finish();
2236
2237 MemoryContextSwitchTo(oldcontext);
2238 elog(ERROR, "RASTER_quantileCoverage: Cannot get raster of coverage");
2239 SRF_RETURN_DONE(funcctx);
2240 }
2241 else if (isNull) {
2242 SPI_cursor_fetch(portal,
TRUE, 1);
2243 continue;
2244 }
2245
2246 pgraster = (
rt_pgraster *) PG_DETOAST_DATUM(datum);
2247
2249 if (!raster) {
2250
2251 SPI_freetuptable(SPI_tuptable);
2252 SPI_cursor_close(portal);
2253 SPI_finish();
2254
2255 MemoryContextSwitchTo(oldcontext);
2256 elog(ERROR, "RASTER_quantileCoverage: Cannot deserialize raster");
2257 SRF_RETURN_DONE(funcctx);
2258 }
2259
2260
2262 if (bandindex < 1 || bandindex > num_bands) {
2263 elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
2264
2266
2267 SPI_freetuptable(SPI_tuptable);
2268 SPI_cursor_close(portal);
2269 SPI_finish();
2270
2271 MemoryContextSwitchTo(oldcontext);
2272 SRF_RETURN_DONE(funcctx);
2273 }
2274
2275
2277 if (!band) {
2278 elog(NOTICE, "Cannot find raster band of index %d. Returning NULL", bandindex);
2279
2281
2282 SPI_freetuptable(SPI_tuptable);
2283 SPI_cursor_close(portal);
2284 SPI_finish();
2285
2286 MemoryContextSwitchTo(oldcontext);
2287 SRF_RETURN_DONE(funcctx);
2288 }
2289
2291 band,
2292 exclude_nodata_value, sample, cov_count,
2293 &qlls, &qlls_count,
2294 quantiles, quantiles_count,
2296 );
2297
2300
2301 if (!covquant || !
count) {
2302 elog(NOTICE, "Cannot compute quantiles for band at index %d", bandindex);
2303
2304 SPI_freetuptable(SPI_tuptable);
2305 SPI_cursor_close(portal);
2306 SPI_finish();
2307
2308 MemoryContextSwitchTo(oldcontext);
2309 SRF_RETURN_DONE(funcctx);
2310 }
2311
2312
2313 SPI_cursor_fetch(portal,
TRUE, 1);
2314 }
2315
2317 for (i = 0; i <
count; i++) {
2320 if (covquant2[i].has_value)
2322 }
2323
2324 pfree(covquant);
2326
2327 if (SPI_tuptable) SPI_freetuptable(SPI_tuptable);
2328 SPI_cursor_close(portal);
2329 SPI_finish();
2330
2331 if (quantiles_count) pfree(quantiles);
2332
2334
2335
2336 funcctx->user_fctx = covquant2;
2337
2338
2339 funcctx->max_calls =
count;
2340
2341
2342 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
2343 ereport(ERROR, (
2344 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2345 errmsg(
2346 "function returning record called in context "
2347 "that cannot accept type record"
2348 )
2349 ));
2350 }
2351
2352 BlessTupleDesc(tupdesc);
2353 funcctx->tuple_desc = tupdesc;
2354
2355 MemoryContextSwitchTo(oldcontext);
2356 }
2357
2358
2359 funcctx = SRF_PERCALL_SETUP();
2360
2361 call_cntr = funcctx->call_cntr;
2362 max_calls = funcctx->max_calls;
2363 tupdesc = funcctx->tuple_desc;
2364 covquant2 = funcctx->user_fctx;
2365
2366
2367 if (call_cntr < max_calls) {
2370 HeapTuple tuple;
2371 Datum result;
2372
2374
2376
2377 values[0] = Float8GetDatum(covquant2[call_cntr].
quantile);
2378 if (covquant2[call_cntr].has_value)
2379 values[1] = Float8GetDatum(covquant2[call_cntr].value);
2380 else
2382
2383
2384 tuple = heap_form_tuple(tupdesc, values, nulls);
2385
2386
2387 result = HeapTupleGetDatum(tuple);
2388
2389 SRF_RETURN_NEXT(funcctx, result);
2390 }
2391
2392 else {
2394 pfree(covquant2);
2395 SRF_RETURN_DONE(funcctx);
2396 }
2397}
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.
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)
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)
#define POSTGIS_RT_DEBUG(level, msg)
#define POSTGIS_RT_DEBUGF(level, msg,...)