[postgis-tickets] r15788 - Make ST_AsMVT tolerant of NULL input and return '':bytea

Paul Ramsey pramsey at cleverelephant.ca
Thu Sep 21 15:11:59 PDT 2017


Author: pramsey
Date: 2017-09-21 15:11:59 -0700 (Thu, 21 Sep 2017)
New Revision: 15788

Modified:
   trunk/postgis/lwgeom_out_mvt.c
   trunk/postgis/mvt.c
   trunk/regress/mvt.sql
   trunk/regress/mvt_expected
Log:
Make ST_AsMVT tolerant of NULL input and return '':bytea
(zero length bytea) when provided with only null inputs, or no 
inputs. (References #3857)


Modified: trunk/postgis/lwgeom_out_mvt.c
===================================================================
--- trunk/postgis/lwgeom_out_mvt.c	2017-09-21 21:45:16 UTC (rev 15787)
+++ trunk/postgis/lwgeom_out_mvt.c	2017-09-21 22:11:59 UTC (rev 15788)
@@ -125,12 +125,16 @@
 	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);

Modified: trunk/postgis/mvt.c
===================================================================
--- trunk/postgis/mvt.c	2017-09-21 21:45:16 UTC (rev 15787)
+++ trunk/postgis/mvt.c	2017-09-21 22:11:59 UTC (rev 15788)
@@ -302,7 +302,9 @@
 	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 @@
 		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_transfn(struct mvt_agg_context *ctx)
 {
-	bool isnull;
+	bool isnull = false;
 	Datum datum;
 	GSERIALIZED *gs;
 	LWGEOM *lwgeom;
@@ -813,21 +814,28 @@
 		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,7 +858,16 @@
 	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);
 

Modified: trunk/regress/mvt.sql
===================================================================
--- trunk/regress/mvt.sql	2017-09-21 21:45:16 UTC (rev 15787)
+++ trunk/regress/mvt.sql	2017-09-21 22:11:59 UTC (rev 15788)
@@ -112,7 +112,24 @@
     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,
     ST_Normalize(ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
@@ -141,6 +158,5 @@
 -- 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;

Modified: trunk/regress/mvt_expected
===================================================================
--- trunk/regress/mvt_expected	2017-09-21 21:45:16 UTC (rev 15787)
+++ trunk/regress/mvt_expected	2017-09-21 22:11:59 UTC (rev 15788)
@@ -29,6 +29,8 @@
 CW90aGVydGVzdCIGCgR0ZXN0KIAgeAI=
 TA8|GkEKBHRlc3QSDBICAAAYASIECTLePxIMEgIAABgBIgQJNNw/EgwSAgABGAEiBAk03D8aAmMxIgIo
 ASICKAIogCB4Ag==
+TA9|0
+TA10|49
 D1|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag==
 D2|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag==
 D3|Gi8KBHRlc3QSDhIEAAABARgBIgQJMt4/GgJjMRoCYzIiAigBIgYKBGFiY2QogCB4Ag==
@@ -38,5 +40,4 @@
 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|



More information about the postgis-tickets mailing list