*
**********************************************************************/
+#include <string.h>
+
#include "mvt.h"
#ifdef HAVE_LIBPROTOBUF
}
}
- ctx->column_cache.column_keys_index[i] = add_key(ctx, pstrdup(tkey));
+ if (ctx->id_name &&
+ (ctx->id_index == UINT32_MAX) &&
+ (strcmp(tkey, ctx->id_name) == 0) &&
+ (typoid == INT2OID || typoid == INT4OID || typoid == INT8OID))
+ {
+ ctx->id_index = i;
+ }
+ else
+ {
+ ctx->column_cache.column_keys_index[i] = add_key(ctx, pstrdup(tkey));
+ }
}
if (!geom_found)
elog(ERROR, "parse_column_keys: no geometry column found");
+
+ if (ctx->id_name != NULL && ctx->id_index == UINT32_MAX)
+ elog(ERROR, "mvt_agg_transfn: Could not find column '%s' of integer type", ctx->id_name);
}
static void encode_keys(mvt_agg_context *ctx)
}
#endif
-static void set_feature_id(mvt_agg_context *ctx, Datum datum)
+/**
+ * Sets the feature id. Ignores Nulls and negative values
+ */
+static void set_feature_id(mvt_agg_context *ctx, Datum datum, bool isNull)
{
- ctx->feature->id = datum;
+ Oid typoid = ctx->column_cache.column_oid[ctx->id_index];
+ int64_t value = INT64_MIN;
+
+ if (isNull)
+ {
+ POSTGIS_DEBUG(3, "set_feature_id: Ignored null value");
+ return;
+ }
+
+ switch (typoid)
+ {
+ case INT2OID:
+ value = DatumGetInt16(datum);
+ break;
+ case INT4OID:
+ value = DatumGetInt32(datum);
+ break;
+ case INT8OID:
+ value = DatumGetInt64(datum);
+ break;
+ default:
+ elog(ERROR, "set_feature_id: Feature id type does not match");
+ }
+
+ if (value < 0)
+ {
+ POSTGIS_DEBUG(3, "set_feature_id: Ignored negative value");
+ return;
+ }
+
ctx->feature->has_id = true;
+ ctx->feature->id = (uint64_t) value;
}
static void parse_values(mvt_agg_context *ctx)
if (i == ctx->geom_index)
continue;
+ if (i == ctx->id_index)
+ {
+ set_feature_id(ctx, datum, cc.nulls[i]);
+ continue;
+ }
+
if (cc.nulls[i])
{
POSTGIS_DEBUG(3, "parse_values isnull detected");
break;
}
- if (ctx->id_name != NULL && strcmp(key, ctx->id_name) == 0 && (typoid == INT2OID || typoid == INT4OID || typoid == INT8OID)) {
- set_feature_id(ctx, datum);
- }
-
ctx->row_columns++;
}
ctx->bool_values_hash = NULL;
ctx->values_hash_i = 0;
ctx->keys_hash_i = 0;
+ ctx->id_index = UINT32_MAX;
ctx->geom_index = UINT32_MAX;
memset(&ctx->column_cache, 0, sizeof(ctx->column_cache));
ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
) AS q;
--- feature id encoding tests
-SELECT 'FI1', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (SELECT 1 AS c1, 'abcd'::text AS c2,
- ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
- ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) 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_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
true
)));
+
+-- Feature id encoding tests
+SELECT 'FI1', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT 1::smallint AS c1, 'abcd'::text AS c2,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+SELECT 'FI2', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT 1::integer AS c1, 'abcd'::text AS c2,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+SELECT 'FI3', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT 1::bigint AS c1, 'abcd'::text AS c2,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+-- Column not found
+SELECT 'FI4', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT 'abcd'::text AS c2,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+-- Column of invalid type
+SELECT 'FI5', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT 2.0 as c1, 'abcd'::text AS c2,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+-- Null value is ignored
+SELECT 'FI6', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT NULL::integer as c1, 'abcd'::text AS c2,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+-- Negative value is ignored
+SELECT 'FI7', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT -5::integer as c1, 'abcd'::text AS c2,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+-- When the column is repeated, the fist one is used as id and the second one is added as a property
+SELECT 'FI8', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT 1::smallint AS c1, 'abcd'::text AS c2, 20::integer as c1,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
+
+-- When the column is repeated: Only the ones with the valid types are considered
+SELECT 'FI9', encode(ST_AsMVT(q, 'test', 4096, 'geom', 'c1'), 'base64') FROM (
+ SELECT 1::double precision AS c1, 'abcd'::text AS c2, 20::integer as c1,
+ ST_AsMVTGeom(ST_GeomFromText('POINT(25 17)'),
+ ST_MakeBox2D(ST_Point(0, 0), ST_Point(4096, 4096)), 4096, 0, false) AS geom
+) AS q;
\ No newline at end of file