32 #include "pgsql_compat.h"
34 #ifdef HAVE_LIBPROTOBUF
35 #include "utils/jsonb.h"
37 #include "lwgeom_wagyu.h"
39 #if POSTGIS_PGSQL_VERSION < 110
41 # define DatumGetJsonbP DatumGetJsonb
44 #define uthash_fatal(msg) lwerror("uthash: fatal error (out of memory)")
45 #define uthash_malloc(sz) palloc(sz)
46 #define uthash_free(ptr,sz) pfree(ptr)
50 #include "vector_tile.pb-c.h"
52 #define FEATURES_CAPACITY_INITIAL 50
76 VectorTile__Tile__Value
value[1];
83 return (
id & 0x7) | (
count << 3);
93 int32_t *px, int32_t *py)
101 for (i = 0; i < pa->
npoints; i++)
146 int32_t px = 0, py = 0;
152 VectorTile__Tile__Feature *feature = ctx->
feature;
153 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POINT;
154 feature->n_geometry = 3;
155 feature->geometry = palloc(
sizeof(*feature->geometry) * 3);
162 VectorTile__Tile__Feature *feature = ctx->
feature;
165 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POINT;
167 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
169 lwline->
points, feature->geometry);
175 VectorTile__Tile__Feature *feature = ctx->
feature;
176 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING;
178 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
180 lwline->
points, feature->geometry);
186 int32_t px = 0, py = 0;
187 size_t c = 0, offset = 0;
188 VectorTile__Tile__Feature *feature = ctx->
feature;
189 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING;
190 for (i = 0; i < lwmline->
ngeoms; i++)
192 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
193 for (i = 0; i < lwmline->
ngeoms; i++)
196 feature->geometry + offset, &px, &py);
197 feature->n_geometry = offset;
203 int32_t px = 0, py = 0;
204 size_t c = 0, offset = 0;
205 VectorTile__Tile__Feature *feature = ctx->
feature;
206 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POLYGON;
207 for (i = 0; i < lwpoly->
nrings; i++)
209 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
210 for (i = 0; i < lwpoly->
nrings; i++)
213 feature->geometry + offset, &px, &py);
214 feature->n_geometry = offset;
220 int32_t px = 0, py = 0;
221 size_t c = 0, offset = 0;
223 VectorTile__Tile__Feature *feature = ctx->
feature;
224 feature->type = VECTOR_TILE__TILE__GEOM_TYPE__POLYGON;
225 for (i = 0; i < lwmpoly->
ngeoms; i++)
226 for (j = 0; poly = lwmpoly->
geoms[i], j < poly->
nrings; j++)
228 feature->geometry = palloc(
sizeof(*feature->geometry) * c);
229 for (i = 0; i < lwmpoly->
ngeoms; i++)
230 for (j = 0; poly = lwmpoly->
geoms[i], j < poly->
nrings; j++)
232 poly->
rings[j], feature->geometry + offset,
234 feature->n_geometry = offset;
255 default: elog(ERROR,
"encode_geometry: '%s' geometry type not supported",
262 Oid tupType = HeapTupleHeaderGetTypeId(ctx->
row);
263 int32 tupTypmod = HeapTupleHeaderGetTypMod(ctx->
row);
264 TupleDesc tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
280 size_t size = strlen(
name);
281 kv = palloc(
sizeof(*kv));
291 bool geom_found =
false;
293 POSTGIS_DEBUG(2,
"parse_column_keys called");
303 for (i = 0; i < natts; i++)
310 if (typoid == JSONBOID)
318 if (!geom_found && typoid == postgis_oid(GEOMETRYOID))
327 if (!geom_found && strcmp(tkey, ctx->
geom_name) == 0)
337 (strcmp(tkey, ctx->
id_name) == 0) &&
338 (typoid == INT2OID || typoid == INT4OID || typoid == INT8OID))
349 elog(ERROR,
"parse_column_keys: no geometry column found");
352 elog(ERROR,
"mvt_agg_transfn: Could not find column '%s' of integer type", ctx->
id_name);
359 char **keys = palloc(n_keys *
sizeof(*keys));
360 for (kv = ctx->
keys_hash; kv != NULL; kv=kv->
hh.next)
362 ctx->
layer->n_keys = n_keys;
363 ctx->
layer->keys = keys;
368 #define MVT_CREATE_VALUES(hash) \
370 struct mvt_kv_value *kv; \
371 for (kv = hash; kv != NULL; kv = kv->hh.next) \
373 values[kv->id] = kv->value; \
379 VectorTile__Tile__Value **values;
380 POSTGIS_DEBUG(2,
"encode_values called");
390 POSTGIS_DEBUGF(3,
"encode_values n_values: %d", ctx->
values_hash_i);
392 ctx->
layer->values = values;
401 #define MVT_PARSE_VALUE(hash, newvalue, size, pfvaluefield, pftype) \
403 POSTGIS_DEBUG(2, "MVT_PARSE_VALUE called"); \
405 struct mvt_kv_value *kv; \
407 HASH_VALUE(&newvalue, size, hashv); \
408 HASH_FIND_BYHASHVALUE(hh, ctx->hash, &newvalue, size, hashv, kv); \
411 POSTGIS_DEBUG(4, "MVT_PARSE_VALUE value not found"); \
412 kv = palloc(sizeof(*kv)); \
413 POSTGIS_DEBUGF(4, "MVT_PARSE_VALUE new hash key: %d", ctx->values_hash_i); \
414 kv->id = ctx->values_hash_i++; \
415 vector_tile__tile__value__init(kv->value); \
416 kv->value->pfvaluefield = newvalue; \
417 kv->value->test_oneof_case = pftype; \
418 HASH_ADD_KEYPTR_BYHASHVALUE(hh, ctx->hash, &kv->value->pfvaluefield, size, hashv, kv); \
420 tags[ctx->row_columns * 2] = k; \
421 tags[ctx->row_columns * 2 + 1] = kv->id; \
425 #define MVT_PARSE_INT_VALUE(value) \
429 uint64_t cvalue = value; \
430 MVT_PARSE_VALUE(uint_values_hash, \
434 VECTOR_TILE__TILE__VALUE__TEST_ONEOF_UINT_VALUE); \
438 int64_t cvalue = value; \
439 MVT_PARSE_VALUE(sint_values_hash, \
443 VECTOR_TILE__TILE__VALUE__TEST_ONEOF_SINT_VALUE); \
447 #define MVT_PARSE_DATUM(type, datumfunc, hash, size, pfvaluefield, pftype) \
449 type value = datumfunc(datum); \
450 MVT_PARSE_VALUE(hash, value, size, pfvaluefield, pftype); \
453 #define MVT_PARSE_INT_DATUM(type, datumfunc) \
455 type value = datumfunc(datum); \
456 MVT_PARSE_INT_VALUE(value); \
465 HASH_VALUE(
value, size, hashv);
466 POSTGIS_DEBUG(2,
"add_value_as_string called");
470 POSTGIS_DEBUG(4,
"add_value_as_string value not found");
471 kv = palloc(
sizeof(*kv));
472 POSTGIS_DEBUGF(4,
"add_value_as_string new hash key: %d",
475 vector_tile__tile__value__init(kv->
value);
477 kv->
value->test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_STRING_VALUE;
502 POSTGIS_DEBUG(2,
"parse_value_as_string called");
503 getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
504 value = OidOutputFunctionCall(foutoid, datum);
505 POSTGIS_DEBUGF(4,
"parse_value_as_string value: %s",
value);
514 bool skipNested =
false;
515 JsonbIteratorToken
r;
518 if (!JB_ROOT_IS_OBJECT(jb))
521 it = JsonbIteratorInit(&jb->root);
523 while ((
r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
527 if (
r == WJB_KEY && v.type != jbvNull)
536 key = palloc(v.val.string.len + 1);
537 memcpy(key, v.val.string.val, v.val.string.len);
538 key[v.val.string.len] =
'\0';
540 tags = repalloc(tags, newSize * 2 *
sizeof(*tags));
544 r = JsonbIteratorNext(&it, &v, skipNested);
546 if (v.type == jbvString)
548 char *
value = palloc(v.val.string.len + 1);
549 memcpy(
value, v.val.string.val, v.val.string.len);
550 value[v.val.string.len] =
'\0';
554 else if (v.type == jbvBool)
558 sizeof(protobuf_c_boolean),
560 VECTOR_TILE__TILE__VALUE__TEST_ONEOF_BOOL_VALUE);
563 else if (v.type == jbvNumeric)
568 str = DatumGetCString(DirectFunctionCall1(numeric_out,
569 PointerGetDatum(v.val.numeric)));
570 d = strtod(
str, NULL);
571 l = strtol(
str, NULL, 10);
573 if (fabs(d - (
double)l) > FLT_EPSILON)
579 VECTOR_TILE__TILE__VALUE__TEST_ONEOF_DOUBLE_VALUE);
599 int64_t
value = INT64_MIN;
603 POSTGIS_DEBUG(3,
"set_feature_id: Ignored null value");
610 value = DatumGetInt16(datum);
613 value = DatumGetInt32(datum);
616 value = DatumGetInt64(datum);
619 elog(ERROR,
"set_feature_id: Feature id type does not match");
624 POSTGIS_DEBUG(3,
"set_feature_id: Ignored negative value");
635 uint32_t *tags = palloc(n_keys * 2 *
sizeof(*tags));
638 uint32_t natts = (uint32_t) cc.
tupdesc->natts;
642 POSTGIS_DEBUG(2,
"parse_values called");
646 tuple.t_len = HeapTupleHeaderGetDatumLength(ctx->
row);
647 ItemPointerSetInvalid(&(tuple.t_self));
648 tuple.t_tableOid = InvalidOid;
649 tuple.t_data = ctx->
row;
654 POSTGIS_DEBUGF(3,
"parse_values natts: %d", natts);
656 for (i = 0; i < natts; i++)
661 Datum datum = cc.
values[i];
674 POSTGIS_DEBUG(3,
"parse_values isnull detected");
678 key = TupleDescAttr(cc.
tupdesc, i)->attname.data;
683 elog(ERROR,
"parse_values: unexpectedly could not find parsed key name '%s'", key);
684 if (typoid == JSONBOID)
696 sizeof(protobuf_c_boolean),
698 VECTOR_TILE__TILE__VALUE__TEST_ONEOF_BOOL_VALUE);
715 VECTOR_TILE__TILE__VALUE__TEST_ONEOF_FLOAT_VALUE);
723 VECTOR_TILE__TILE__VALUE__TEST_ONEOF_DOUBLE_VALUE);
743 POSTGIS_DEBUGF(3,
"parse_values n_tags %zd", ctx->
feature->n_tags);
762 return geom->
type - 3;
769 for (i = 0; i < g->
ngeoms; i++)
777 elog(ERROR,
"%s: Invalid type (%d)", __func__, geom->
type);
804 geom_out = g->
geoms[0];
825 POSTGIS_DEBUG(3,
"mvt_geom: geometry outside clip box");
831 POSTGIS_DEBUG(3,
"mvt_geom: geometry contained fully inside the box");
854 gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
893 clipped_lwgeom = lwgeom_wagyu_clip_by_box(lwgeom, &clip_box);
895 return clipped_lwgeom;
909 AFFINE affine = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
910 gridspec grid = {0, 0, 0, 0, 1, 1, 0, 0};
911 double width = gbox->
xmax - gbox->
xmin;
912 double height = gbox->
ymax - gbox->
ymin;
916 POSTGIS_DEBUG(2,
"mvt_geom called");
926 fy = -(extent / height);
965 VectorTile__Tile__Layer *layer;
967 POSTGIS_DEBUG(2,
"mvt_agg_init_context called");
970 elog(ERROR,
"mvt_agg_init_context: extent cannot be 0");
988 layer = palloc(
sizeof(*layer));
989 vector_tile__tile__layer__init(layer);
991 layer->name = ctx->
name;
992 layer->extent = ctx->
extent;
1007 bool isnull =
false;
1011 VectorTile__Tile__Feature *feature;
1012 VectorTile__Tile__Layer *layer = ctx->
layer;
1014 POSTGIS_DEBUG(2,
"mvt_agg_transfn called");
1019 layer->features = repalloc(layer->features, new_capacity *
1020 sizeof(*layer->features));
1022 POSTGIS_DEBUGF(3,
"mvt_agg_transfn new_capacity: %zd", new_capacity);
1028 datum = GetAttributeByNum(ctx->
row, ctx->
geom_index + 1, &isnull);
1029 POSTGIS_DEBUGF(3,
"mvt_agg_transfn ctx->geom_index: %d", ctx->
geom_index);
1030 POSTGIS_DEBUGF(3,
"mvt_agg_transfn isnull: %u", isnull);
1031 POSTGIS_DEBUGF(3,
"mvt_agg_transfn datum: %lu", datum);
1034 POSTGIS_DEBUG(3,
"mvt_agg_transfn got null geom");
1038 feature = palloc(
sizeof(*feature));
1039 vector_tile__tile__feature__init(feature);
1046 POSTGIS_DEBUGF(3,
"mvt_agg_transfn encoded feature count: %zd", layer->n_features);
1047 layer->features[layer->n_features++] = feature;
1058 VectorTile__Tile *tile;
1062 tile = palloc(
sizeof(VectorTile__Tile));
1063 vector_tile__tile__init(tile);
1064 tile->layers = palloc(
sizeof(VectorTile__Tile__Layer*) * n_layers);
1065 tile->layers[0] = ctx->
layer;
1066 tile->n_layers = n_layers;
1085 if (ctx && ctx->
layer && ctx->
layer->n_features == 0)
1087 bytea *ba = palloc(VARHDRSZ);
1088 SET_VARSIZE(ba, VARHDRSZ);
1093 len = VARHDRSZ + vector_tile__tile__get_packed_size(ctx->
tile);
1095 vector_tile__tile__pack(ctx->
tile, (uint8_t*)VARDATA(ba));
1096 SET_VARSIZE(ba, len);
1108 return palloc(size);
1118 ProtobufCAllocator allocator =
1125 size_t len = VARSIZE_ANY_EXHDR(ba);
1126 VectorTile__Tile *tile = vector_tile__tile__unpack(&allocator, len, (uint8_t*)VARDATA(ba));
1140 static VectorTile__Tile__Layer *
1143 const uint32_t key_offset = layer->n_keys;
1144 const uint32_t value_offset = layer->n_values;
1145 const uint32_t feature_offset = layer->n_features;
1149 layer->keys = layer2->keys;
1150 layer->n_keys = layer2->n_keys;
1152 else if (layer2->n_keys)
1154 layer->keys = repalloc(layer->keys,
sizeof(
char *) * (layer->n_keys + layer2->n_keys));
1155 memcpy(&layer->keys[key_offset], layer2->keys,
sizeof(
char *) * layer2->n_keys);
1156 layer->n_keys += layer2->n_keys;
1159 if (!layer->n_values)
1161 layer->values = layer2->values;
1162 layer->n_values = layer2->n_values;
1164 else if (layer2->n_values)
1167 repalloc(layer->values,
sizeof(VectorTile__Tile__Value *) * (layer->n_values + layer2->n_values));
1169 &layer->values[value_offset], layer2->values,
sizeof(VectorTile__Tile__Value *) * layer2->n_values);
1170 layer->n_values += layer2->n_values;
1173 if (!layer->n_features)
1175 layer->features = layer2->features;
1176 layer->n_features = layer2->n_features;
1178 else if (layer2->n_features)
1180 layer->features = repalloc(
1181 layer->features,
sizeof(VectorTile__Tile__Feature *) * (layer->n_features + layer2->n_features));
1182 memcpy(&layer->features[feature_offset], layer2->features,
sizeof(
char *) * layer2->n_features);
1183 layer->n_features += layer2->n_features;
1185 for (uint32_t i = feature_offset; i < layer->n_features; i++)
1187 for (uint32_t t = 0; t < layer->features[i]->n_tags; t += 2)
1189 layer->features[i]->tags[t] += key_offset;
1190 layer->features[i]->tags[t + 1] += value_offset;
1199 static VectorTile__Tile *
1203 VectorTile__Tile *tile;
1206 if (tile1->n_layers == 0 && tile2->n_layers == 0)
1208 else if (tile1->n_layers == 0)
1210 else if (tile2->n_layers == 0)
1213 tile = palloc(
sizeof(VectorTile__Tile));
1214 vector_tile__tile__init(tile);
1215 tile->layers = palloc(
sizeof(
void*));
1219 for (i = 0; i < tile1->n_layers; i++)
1221 for (j = 0; j < tile2->n_layers; j++)
1223 VectorTile__Tile__Layer *l1 = tile1->layers[i];
1224 VectorTile__Tile__Layer *l2 = tile2->layers[j];
1225 if (strcmp(l1->name, l2->name)==0)
1230 tile->layers[tile->n_layers++] = layer;
1232 tile->layers = repalloc(tile->layers, (tile->n_layers+1) *
sizeof(
void*));
1243 if (ctx1 && ! ctx2)
return ctx1;
1244 if (ctx2 && ! ctx1)
return ctx2;
1245 if (ctx1 && ctx2 && ctx1->
tile && ctx2->
tile)
1254 elog(DEBUG2,
"ctx1->tile = %p", ctx1->
tile);
1255 elog(DEBUG2,
"ctx2->tile = %p", ctx2->
tile);
1256 elog(ERROR,
"%s: unable to combine contexts where tile attribute is null", __func__);
int gbox_overlaps_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps on the 2d plane, LW_FALSE otherwise.
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
int gbox_contains_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the first GBOX contains the second on the 2d plane, LW_FALSE otherwise.
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int lwgeom_simplify_in_place(LWGEOM *igeom, double dist, int preserve_collapsed)
void lwgeom_free(LWGEOM *geom)
int lwgeom_remove_repeated_points_in_place(LWGEOM *in, double tolerance)
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
LWCOLLECTION * lwcollection_extract(const LWCOLLECTION *col, uint32_t type)
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
LWLINE * lwline_from_lwmpoint(int32_t srid, const LWMPOINT *mpoint)
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
#define FLAGS_SET_GEODETIC(flags, value)
LWGEOM * lwgeom_clip_by_rect(const LWGEOM *geom1, double x0, double y0, double x1, double y1)
void lwgeom_grid_in_place(LWGEOM *lwgeom, const gridspec *grid)
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
static void encode_poly(mvt_agg_context *ctx, LWPOLY *lwpoly)
static uint32_t get_key_index_with_size(mvt_agg_context *ctx, const char *name, size_t size)
static void encode_mline(mvt_agg_context *ctx, LWMLINE *lwmline)
static void parse_datum_as_string(mvt_agg_context *ctx, Oid typoid, Datum datum, uint32_t *tags, uint32_t k)
static void encode_geometry(mvt_agg_context *ctx, LWGEOM *lwgeom)
static VectorTile__Tile__Layer * vectortile_layer_combine(VectorTile__Tile__Layer *layer, VectorTile__Tile__Layer *layer2)
Combine 2 layers.
#define MVT_PARSE_INT_VALUE(value)
mvt_agg_context * mvt_ctx_combine(mvt_agg_context *ctx1, mvt_agg_context *ctx2)
static void encode_mpoly(mvt_agg_context *ctx, LWMPOLY *lwmpoly)
mvt_agg_context * mvt_ctx_deserialize(const bytea *ba)
#define MVT_PARSE_DATUM(type, datumfunc, hash, size, pfvaluefield, pftype)
LWGEOM * mvt_geom(LWGEOM *lwgeom, const GBOX *gbox, uint32_t extent, uint32_t buffer, bool clip_geom)
Transform a geometry into vector tile coordinate space.
static void encode_mpoint(mvt_agg_context *ctx, LWMPOINT *mpoint)
#define FEATURES_CAPACITY_INITIAL
static void set_feature_id(mvt_agg_context *ctx, Datum datum, bool isNull)
Sets the feature id.
static void encode_keys(mvt_agg_context *ctx)
static LWGEOM * mvt_unsafe_clip_by_box(LWGEOM *lwg_in, GBOX *clip_box)
static void encode_point(mvt_agg_context *ctx, LWPOINT *point)
#define MVT_PARSE_INT_DATUM(type, datumfunc)
#define MVT_CREATE_VALUES(hash)
bytea * mvt_agg_finalfn(mvt_agg_context *ctx)
Finalize aggregation.
bytea * mvt_ctx_serialize(mvt_agg_context *ctx)
static void mvt_deallocator(__attribute__((__unused__)) void *data, void *ptr)
static uint32_t * parse_jsonb(mvt_agg_context *ctx, Jsonb *jb, uint32_t *tags)
static void parse_column_keys(mvt_agg_context *ctx)
static bool add_value_as_string_with_size(mvt_agg_context *ctx, char *value, size_t size, uint32_t *tags, uint32_t k)
static uint32_t c_int(enum mvt_cmd_id id, uint32_t count)
static VectorTile__Tile * mvt_ctx_to_tile(mvt_agg_context *ctx)
static uint32_t add_key(mvt_agg_context *ctx, char *name)
static LWGEOM * mvt_clip_and_validate_geos(LWGEOM *lwgeom, uint8_t basic_type, uint32_t extent, uint32_t buffer, bool clip_geom)
static LWGEOM * lwgeom_to_basic_type(LWGEOM *geom, uint8_t original_type)
In place process a collection to find a concrete geometry object and expose that as the actual object...
static void * mvt_allocator(__attribute__((__unused__)) void *data, size_t size)
void mvt_agg_init_context(mvt_agg_context *ctx)
Initialize aggregation context.
static bytea * mvt_ctx_to_bytea(mvt_agg_context *ctx)
static TupleDesc get_tuple_desc(mvt_agg_context *ctx)
static uint32_t encode_ptarray_initial(mvt_agg_context *ctx, enum mvt_type type, POINTARRAY *pa, uint32_t *buffer)
#define MVT_PARSE_VALUE(hash, newvalue, size, pfvaluefield, pftype)
static uint8_t lwgeom_get_basic_type(LWGEOM *geom)
static LWGEOM * mvt_clip_and_validate(LWGEOM *lwgeom, uint8_t basic_type, uint32_t extent, uint32_t buffer, bool clip_geom)
static VectorTile__Tile * vectortile_tile_combine(VectorTile__Tile *tile1, VectorTile__Tile *tile2)
void mvt_agg_transfn(mvt_agg_context *ctx)
Aggregation step.
static void parse_values(mvt_agg_context *ctx)
static void add_value_as_string(mvt_agg_context *ctx, char *value, uint32_t *tags, uint32_t k)
static void encode_values(mvt_agg_context *ctx)
static uint32_t p_int(int32_t value)
static void encode_line(mvt_agg_context *ctx, LWLINE *lwline)
static uint32_t encode_ptarray(__attribute__((__unused__)) mvt_agg_context *ctx, enum mvt_type type, POINTARRAY *pa, uint32_t *buffer, int32_t *px, int32_t *py)
Datum buffer(PG_FUNCTION_ARGS)
struct mvt_kv_value * uint_values_hash
VectorTile__Tile__Layer * layer
VectorTile__Tile__Feature * feature
struct mvt_kv_key * keys_hash
struct mvt_kv_value * float_values_hash
struct mvt_kv_value * bool_values_hash
struct mvt_kv_value * string_values_hash
struct mvt_kv_value * double_values_hash
mvt_column_cache column_cache
struct mvt_kv_value * sint_values_hash
uint32_t * column_keys_index
VectorTile__Tile__Value value[1]