From 2ee9aa3336c9d657f842d7795668822b7e9194b9 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Thu, 21 Sep 2017 22:11:59 +0000 Subject: [PATCH] Make ST_AsMVT tolerant of NULL input and return '':bytea (zero length bytea) when provided with only null inputs, or no inputs. (References #3857) git-svn-id: http://svn.osgeo.org/postgis/trunk@15788 b70326c6-7e19-0410-871a-916f4a2858ee --- postgis/lwgeom_out_mvt.c | 8 ++++++-- postgis/mvt.c | 41 ++++++++++++++++++++++++++++------------ regress/mvt.sql | 20 ++++++++++++++++++-- regress/mvt_expected | 5 +++-- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/postgis/lwgeom_out_mvt.c b/postgis/lwgeom_out_mvt.c index 7e886eadb..945d901c4 100644 --- a/postgis/lwgeom_out_mvt.c +++ b/postgis/lwgeom_out_mvt.c @@ -125,12 +125,16 @@ Datum pgis_asmvt_finalfn(PG_FUNCTION_ARGS) PG_RETURN_NULL(); #else struct mvt_agg_context *ctx; - uint8_t *buf; + bytea *buf; if (!AggCheckCallContext(fcinfo, NULL)) elog(ERROR, "pgis_asmvt_finalfn called in non-aggregate context"); if (PG_ARGISNULL(0)) - PG_RETURN_NULL(); + { + bytea *emptybuf = palloc(VARHDRSZ); + SET_VARSIZE(emptybuf, VARHDRSZ); + PG_RETURN_BYTEA_P(emptybuf); + } ctx = (struct mvt_agg_context *) PG_GETARG_POINTER(0); buf = mvt_agg_finalfn(ctx); diff --git a/postgis/mvt.c b/postgis/mvt.c index 613d69a64..0ef1401ae 100644 --- a/postgis/mvt.c +++ b/postgis/mvt.c @@ -302,7 +302,9 @@ static void parse_column_keys(struct mvt_agg_context *ctx) int natts = tupdesc->natts; uint32_t i; bool geom_found = false; + char *key; POSTGIS_DEBUG(2, "parse_column_keys called"); + for (i = 0; i < natts; i++) { #if POSTGIS_PGSQL_VERSION < 110 Oid typoid = getBaseType(tupdesc->attrs[i]->atttypid); @@ -315,18 +317,17 @@ static void parse_column_keys(struct mvt_agg_context *ctx) if (typoid == JSONBOID) continue; #endif - char *key = palloc(strlen(tkey) + 1); - strcpy(key, tkey); + key = pstrdup(tkey); if (ctx->geom_name == NULL) { if (!geom_found && typoid == TypenameGetTypid("geometry")) { ctx->geom_index = i; - geom_found = 1; + geom_found = true; continue; } } else { if (!geom_found && strcmp(key, ctx->geom_name) == 0) { ctx->geom_index = i; - geom_found = 1; + geom_found = true; continue; } } @@ -796,7 +797,7 @@ void mvt_agg_init_context(struct mvt_agg_context *ctx)  */ void mvt_agg_transfn(struct mvt_agg_context *ctx) { - bool isnull; + bool isnull = false; Datum datum; GSERIALIZED *gs; LWGEOM *lwgeom; @@ -813,21 +814,28 @@ void mvt_agg_transfn(struct mvt_agg_context *ctx) POSTGIS_DEBUGF(3, "mvt_agg_transfn new_capacity: %zd", new_capacity); } + if (layer->n_features == 0) + parse_column_keys(ctx); + + datum = GetAttributeByNum(ctx->row, ctx->geom_index + 1, &isnull); + POSTGIS_DEBUGF(3, "mvt_agg_transfn ctx->geom_index: %d", ctx->geom_index); + POSTGIS_DEBUGF(3, "mvt_agg_transfn isnull: %u", isnull); + POSTGIS_DEBUGF(3, "mvt_agg_transfn datum: %lu", datum); + if (isnull) /* Skip rows that have null geometry */ + { + POSTGIS_DEBUG(3, "mvt_agg_transfn got null geom"); + return; + } + feature = palloc(sizeof(*feature)); vector_tile__tile__feature__init(feature); ctx->feature = feature; - if (layer->n_features == 0) - parse_column_keys(ctx); - datum = GetAttributeByNum(ctx->row, ctx->geom_index + 1, &isnull); - if (!datum) - elog(ERROR, "mvt_agg_transfn: geometry column cannot be null"); gs = (GSERIALIZED *) PG_DETOAST_DATUM(datum); lwgeom = lwgeom_from_gserialized(gs); - POSTGIS_DEBUGF(3, "mvt_agg_transfn encoded feature count: %zd", - layer->n_features); + POSTGIS_DEBUGF(3, "mvt_agg_transfn encoded feature count: %zd", layer->n_features); layer->features[layer->n_features++] = feature; encode_geometry(ctx, lwgeom); @@ -850,6 +858,15 @@ uint8_t *mvt_agg_finalfn(struct mvt_agg_context *ctx) uint8_t *buf; POSTGIS_DEBUG(2, "mvt_agg_finalfn called"); + POSTGIS_DEBUGF(2, "mvt_agg_finalfn n_features == %zd", ctx->layer->n_features); + + /* Zero features => empty bytea output */ + if (ctx->layer->n_features == 0) + { + buf = palloc(VARHDRSZ); + SET_VARSIZE(buf, VARHDRSZ); + return buf; + } encode_keys(ctx); encode_values(ctx); diff --git a/regress/mvt.sql b/regress/mvt.sql index f7baa1318..dd8239db2 100644 --- a/regress/mvt.sql +++ b/regress/mvt.sql @@ -112,6 +112,23 @@ SELECT 'TA8', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM ( UNION SELECT 2::int AS c1, ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(26 18)'), ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false)) AS geom) AS q; +SELECT 'TA9', length(ST_AsMVT(q)) +FROM ( + SELECT 1 AS c1, -1 AS c2, + ST_Normalize(ST_AsMVTGeom( + 'POINT(25 17)'::geometry, + ST_MakeBox2D(ST_Point(0, 0), ST_Point(4, 4)) + )) AS geom +) AS q; +SELECT 'TA10', length(ST_AsMVT(q)) +FROM ( + SELECT 1 AS c1, -1 AS c2, + ST_Normalize(ST_AsMVTGeom( + 'POINT(25 17)'::geometry, + ST_MakeBox2D(ST_Point(0, 0), ST_Point(48, 48)) + )) AS geom +) AS q; + -- default values tests SELECT 'D1', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT 1 AS c1, 'abcd'::text AS c2, @@ -141,6 +158,5 @@ select 'D7', ST_AsText(ST_Normalize(ST_AsMVTGeom( -- unsupported input SELECT 'TU2'; SELECT encode(ST_AsMVT(1, 'test', 4096, 'geom'), 'base64'); -SELECT 'TU3'; -SELECT encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') +SELECT 'TU3', encode(ST_AsMVT(q, 'test', 4096, 'geom'), 'base64') FROM (SELECT NULL::integer AS c1, NULL AS geom) AS q; diff --git a/regress/mvt_expected b/regress/mvt_expected index e94c0de34..4b699cc7c 100644 --- a/regress/mvt_expected +++ b/regress/mvt_expected @@ -29,6 +29,8 @@ TA7|Gk4KBHRlc3QSDBICAAAYASIECTTcPxIMEgIAARgBIgQJMt4/EgwSAgABGAEiBAk03D8aAmMxIgsK CW90aGVydGVzdCIGCgR0ZXN0KIAgeAI= TA8|GkEKBHRlc3QSDBICAAAYASIECTLePxIMEgIAABgBIgQJNNw/EgwSAgABGAEiBAk03D8aAmMxIgIo ASICKAIogCB4Ag== +TA9|0 +TA10|49 D1|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag== D2|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag== D3|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag== @@ -38,5 +40,4 @@ D6|POINT(1 4094) D7|POINT(1 4094) TU2 ERROR: pgis_asmvt_transfn: parameter row cannot be other than a rowtype -TU3 -ERROR: mvt_agg_transfn: geometry column cannot be null +TU3| -- 2.50.0