28 #include "parser/parse_type.h"
30 #include "utils/timestamp.h"
31 #include "miscadmin.h"
32 #include "utils/date.h"
33 #include "utils/datetime.h"
34 #include "utils/jsonb.h"
40 return flatgeobuf_column_type_bool;
42 return flatgeobuf_column_type_short;
44 return flatgeobuf_column_type_int;
46 return flatgeobuf_column_type_long;
48 return flatgeobuf_column_type_float;
50 return flatgeobuf_column_type_double;
53 return flatgeobuf_column_type_string;
55 return flatgeobuf_column_type_json;
57 return flatgeobuf_column_type_binary;
62 return flatgeobuf_column_type_datetime;
64 elog(ERROR,
"flatgeobuf: get_column_type: '%d' column type not supported",
71 flatgeobuf_column **columns;
72 uint32_t columns_size = 0;
73 Oid tupType = HeapTupleHeaderGetTypeId(ctx->
row);
74 int32 tupTypmod = HeapTupleHeaderGetTypMod(ctx->
row);
75 TupleDesc tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
76 int natts = tupdesc->natts;
77 bool geom_found =
false;
79 POSTGIS_DEBUG(2,
"calling inspect_table");
81 columns = palloc(
sizeof(flatgeobuf_column *) * natts);
86 for (
int i = 0; i < natts; i++) {
87 Oid typoid = getBaseType(TupleDescAttr(tupdesc, i)->atttypid);
88 const char *key = TupleDescAttr(tupdesc, i)->attname.data;
89 POSTGIS_DEBUGF(2,
"inspecting column definition for %s with oid %d", key, typoid);
91 if (!geom_found && typoid == postgis_oid(GEOMETRYOID)) {
97 if (!geom_found && strcmp(key, ctx->
geom_name) == 0) {
103 POSTGIS_DEBUGF(2,
"creating column definition for %s with oid %d", key, typoid);
105 c = (flatgeobuf_column *) palloc0(
sizeof(flatgeobuf_column));
106 c->name = pstrdup(key);
108 columns[columns_size] = c;
113 elog(ERROR,
"no geom column found");
115 if (columns_size > 0) {
116 ctx->
ctx->columns = columns;
117 ctx->
ctx->columns_size = columns_size;
124 if (ctx->
ctx->properties_size == 0) {
125 ctx->
ctx->properties_size = 1024 * 4;
126 POSTGIS_DEBUGF(2,
"flatgeobuf: properties buffer to size %d", ctx->
ctx->properties_size);
127 ctx->
ctx->properties = palloc(ctx->
ctx->properties_size);
129 if (ctx->
ctx->properties_size < size) {
130 ctx->
ctx->properties_size = ctx->
ctx->properties_size * 2;
131 POSTGIS_DEBUGF(2,
"flatgeobuf: reallocating properties buffer to size %d", ctx->
ctx->properties_size);
132 ctx->
ctx->properties = repalloc(ctx->
ctx->properties, ctx->
ctx->properties_size);
140 if (ctx->
ctx->features_count == 0) {
141 ctx->
ctx->items_len = 32;
142 ctx->
ctx->items = palloc(
sizeof(flatgeobuf_item *) * ctx->
ctx->items_len);
144 if (ctx->
ctx->items_len < (ctx->
ctx->features_count + 1)) {
145 ctx->
ctx->items_len = ctx->
ctx->items_len * 2;
146 POSTGIS_DEBUGF(2,
"flatgeobuf: reallocating items to len %lld", ctx->
ctx->items_len);
147 ctx->
ctx->items = repalloc(ctx->
ctx->items,
sizeof(flatgeobuf_item *) * ctx->
ctx->items_len);
172 for (i = 0; i < (uint32_t) ctx->
tupdesc->natts; i++) {
175 datum = GetAttributeByNum(ctx->
row, i + 1, &isnull);
179 memcpy(ctx->
ctx->properties + offset, &ci,
sizeof(ci));
180 offset +=
sizeof(ci);
181 typoid = getBaseType(TupleDescAttr(ctx->
tupdesc, i)->atttypid);
184 byte_value = DatumGetBool(datum) ? 1 : 0;
186 memcpy(ctx->
ctx->properties + offset, &byte_value,
sizeof(byte_value));
187 offset +=
sizeof(byte_value);
190 short_value = DatumGetInt16(datum);
192 memcpy(ctx->
ctx->properties + offset, &short_value,
sizeof(short_value));
193 offset +=
sizeof(short_value);
196 int_value = DatumGetInt32(datum);
198 memcpy(ctx->
ctx->properties + offset, &int_value,
sizeof(int_value));
199 offset +=
sizeof(int_value);
202 long_value = DatumGetInt64(datum);
204 memcpy(ctx->
ctx->properties + offset, &long_value,
sizeof(long_value));
205 offset +=
sizeof(long_value);
208 float_value = DatumGetFloat4(datum);
210 memcpy(ctx->
ctx->properties + offset, &float_value,
sizeof(float_value));
211 offset +=
sizeof(float_value);
214 double_value = DatumGetFloat8(datum);
216 memcpy(ctx->
ctx->properties + offset, &double_value,
sizeof(double_value));
217 offset +=
sizeof(double_value);
220 string_value = text_to_cstring(DatumGetTextP(datum));
221 len = strlen(string_value);
223 memcpy(ctx->
ctx->properties + offset, &len,
sizeof(len));
224 offset +=
sizeof(len);
226 memcpy(ctx->
ctx->properties + offset, string_value, len);
229 case TIMESTAMPTZOID: {
233 const char *tzn = NULL;
234 TimestampTz timestamp;
235 timestamp = DatumGetTimestampTz(datum);
236 timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL);
237 string_value = palloc(MAXDATELEN + 1);
238 EncodeDateTime(&tm, fsec,
true, tz, tzn, USE_ISO_DATES, string_value);
239 len = strlen(string_value);
241 memcpy(ctx->
ctx->properties + offset, &len,
sizeof(len));
242 offset +=
sizeof(len);
244 memcpy(ctx->
ctx->properties + offset, string_value, len);
263 POSTGIS_DEBUGF(3,
"offset %ld", offset);
264 ctx->
ctx->properties_len = offset;
270 uint8_t *buf = ctx->
ctx->buf + ctx->
ctx->offset;
273 for (i = 0; i < FLATGEOBUF_MAGICBYTES_SIZE / 2; i++)
274 if (buf[i] != flatgeobuf_magicbytes[i])
275 elog(ERROR,
"Data is not FlatGeobuf");
276 ctx->
ctx->offset += FLATGEOBUF_MAGICBYTES_SIZE;
282 flatgeobuf_column *column;
285 uint8_t *
data = ctx->
ctx->properties;
286 uint32_t size = ctx->
ctx->properties_len;
288 POSTGIS_DEBUGF(3,
"flatgeobuf: decode_properties from byte array with length %d at offset %d", size, offset);
292 if (size > 0 && size < (
sizeof(uint16_t) +
sizeof(uint8_t)))
293 elog(ERROR,
"flatgeobuf: decode_properties: Unexpected properties data size %d", size);
294 while (offset + 1 < size) {
295 if (offset +
sizeof(uint16_t) > size)
296 elog(ERROR,
"flatgeobuf: decode_properties: Unexpected offset %d", offset);
297 memcpy(&i,
data + offset,
sizeof(uint16_t));
299 offset +=
sizeof(uint16_t);
300 if (i >= ctx->
ctx->columns_size)
301 elog(ERROR,
"flatgeobuf: decode_properties: Column index %hu out of range", i);
302 column = ctx->
ctx->columns[i];
306 case flatgeobuf_column_type_bool: {
308 if (offset +
sizeof(uint8_t) > size)
309 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for bool value");
310 memcpy(&
value,
data + offset,
sizeof(uint8_t));
311 values[ci] = BoolGetDatum(
value);
312 offset +=
sizeof(uint8_t);
315 case flatgeobuf_column_type_byte: {
317 if (offset +
sizeof(int8_t) > size)
318 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for byte value");
319 memcpy(&
value,
data + offset,
sizeof(int8_t));
320 values[ci] = Int8GetDatum(
value);
321 offset +=
sizeof(int8_t);
324 case flatgeobuf_column_type_ubyte: {
326 if (offset +
sizeof(uint8_t) > size)
327 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for ubyte value");
328 memcpy(&
value,
data + offset,
sizeof(uint8_t));
329 values[ci] = UInt8GetDatum(
value);
330 offset +=
sizeof(uint8_t);
333 case flatgeobuf_column_type_short: {
335 if (offset +
sizeof(int16_t) > size)
336 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for short value");
337 memcpy(&
value,
data + offset,
sizeof(int16_t));
338 values[ci] = Int16GetDatum(
value);
339 offset +=
sizeof(int16_t);
342 case flatgeobuf_column_type_ushort: {
344 if (offset +
sizeof(uint16_t) > size)
345 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for ushort value");
346 memcpy(&
value,
data + offset,
sizeof(uint16_t));
347 values[ci] = UInt16GetDatum(
value);
348 offset +=
sizeof(uint16_t);
351 case flatgeobuf_column_type_int: {
353 if (offset +
sizeof(int32_t) > size)
354 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for int value");
355 memcpy(&
value,
data + offset,
sizeof(int32_t));
356 values[ci] = Int32GetDatum(
value);
357 offset +=
sizeof(int32_t);
360 case flatgeobuf_column_type_uint: {
362 if (offset +
sizeof(uint32_t) > size)
363 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for uint value");
364 memcpy(&
value,
data + offset,
sizeof(uint32_t));
365 values[ci] = UInt32GetDatum(
value);
366 offset +=
sizeof(uint32_t);
369 case flatgeobuf_column_type_long: {
371 if (offset +
sizeof(int64_t) > size)
372 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for long value");
373 memcpy(&
value,
data + offset,
sizeof(int64_t));
374 values[ci] = Int64GetDatum(
value);
375 offset +=
sizeof(int64_t);
378 case flatgeobuf_column_type_ulong: {
380 if (offset +
sizeof(uint64_t) > size)
381 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for ulong value");
382 memcpy(&
value,
data + offset,
sizeof(uint64_t));
383 values[ci] = UInt64GetDatum(
value);
384 offset +=
sizeof(uint64_t);
387 case flatgeobuf_column_type_float: {
389 if (offset +
sizeof(
float) > size)
390 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for float value");
391 memcpy(&
value,
data + offset,
sizeof(
float));
392 values[ci] = Float4GetDatum(
value);
393 offset +=
sizeof(float);
396 case flatgeobuf_column_type_double: {
398 if (offset +
sizeof(
double) > size)
399 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for double value");
400 memcpy(&
value,
data + offset,
sizeof(
double));
401 values[ci] = Float8GetDatum(
value);
402 offset +=
sizeof(double);
405 case flatgeobuf_column_type_string: {
407 if (offset +
sizeof(len) > size)
408 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for string value");
409 memcpy(&len,
data + offset,
sizeof(uint32_t));
410 offset +=
sizeof(len);
411 values[ci] = PointerGetDatum(cstring_to_text_with_len((
const char *)
data + offset, len));
415 case flatgeobuf_column_type_datetime: {
418 char workbuf[MAXDATELEN + MAXDATEFIELDS];
419 char *field[MAXDATEFIELDS];
420 int ftype[MAXDATEFIELDS];
423 struct pg_tm tt, *tm = &tt;
427 #if POSTGIS_PGSQL_VERSION >= 160
428 DateTimeErrorExtra extra;
430 if (offset +
sizeof(len) > size)
431 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for string value");
432 memcpy(&len,
data + offset,
sizeof(uint32_t));
433 offset +=
sizeof(len);
434 buf = palloc0(len + 1);
435 memcpy(buf, (
const char *)
data + offset, len);
436 ParseDateTime((
const char *) buf, workbuf,
sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf);
438 #if POSTGIS_PGSQL_VERSION >= 160
439 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp, &extra);
441 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
443 tm2timestamp(tm, fsec, &tzp, &dttz);
444 values[ci] = TimestampTzGetDatum(dttz);
458 elog(ERROR,
"flatgeobuf: decode_properties: Unknown type %d",
type);
467 uint32_t natts = ctx->
tupdesc->natts;
469 Datum *values = palloc0(natts *
sizeof(Datum *));
470 bool *isnull = palloc0(natts *
sizeof(
bool *));
472 values[0] = Int32GetDatum(ctx->
fid);
474 if (flatgeobuf_decode_feature(ctx->
ctx))
475 elog(ERROR,
"flatgeobuf_decode_feature: unsuccessful");
477 if (ctx->
ctx->lwgeom != NULL) {
478 values[1] = PointerGetDatum(geometry_serialize(ctx->
ctx->lwgeom));
480 POSTGIS_DEBUG(3,
"geometry is null");
484 if (natts > 2 && ctx->
ctx->properties_len > 0)
487 heapTuple = heap_form_tuple(ctx->
tupdesc, values, isnull);
488 ctx->
result = HeapTupleGetDatum(heapTuple);
491 POSTGIS_DEBUGF(3,
"fid now %d", ctx->
fid);
493 if (ctx->
ctx->offset == ctx->
ctx->size) {
494 POSTGIS_DEBUGF(3,
"reached end at %lld", ctx->
ctx->offset);
505 size_t size = VARHDRSZ + FLATGEOBUF_MAGICBYTES_SIZE;
506 ctx = palloc0(
sizeof(*
ctx));
507 ctx->ctx = palloc0(
sizeof(flatgeobuf_ctx));
509 memcpy(
ctx->ctx->buf + VARHDRSZ, flatgeobuf_magicbytes, FLATGEOBUF_MAGICBYTES_SIZE);
512 ctx->ctx->features_count = 0;
513 ctx->ctx->offset = size;
515 ctx->ctx->create_index = create_index;
533 if (
ctx->ctx->features_count == 0)
536 datum = GetAttributeByNum(
ctx->row,
ctx->geom_index + 1, &isnull);
541 ctx->ctx->lwgeom = lwgeom;
543 if (
ctx->ctx->features_count == 0)
544 flatgeobuf_encode_header(
ctx->ctx);
547 if (
ctx->ctx->create_index)
549 flatgeobuf_encode_feature(
ctx->ctx);
559 POSTGIS_DEBUGF(3,
"called at offset %lld",
ctx->ctx->offset);
563 if (
ctx->ctx->features_count == 0) {
564 flatgeobuf_encode_header(
ctx->ctx);
565 }
else if (
ctx->ctx->create_index) {
566 ctx->ctx->index_node_size = 16;
567 flatgeobuf_create_index(
ctx->ctx);
569 if (
ctx->tupdesc != NULL)
570 ReleaseTupleDesc(
ctx->tupdesc);
571 SET_VARSIZE(
ctx->ctx->buf,
ctx->ctx->offset);
572 return ctx->ctx->buf;
uint8_t * flatgeobuf_agg_finalfn(struct flatgeobuf_agg_ctx *ctx)
Finalize aggregation.
void flatgeobuf_check_magicbytes(struct flatgeobuf_decode_ctx *ctx)
static void inspect_table(struct flatgeobuf_agg_ctx *ctx)
static void encode_properties(flatgeobuf_agg_ctx *ctx)
static uint8_t get_column_type(Oid typoid)
static void ensure_items_len(struct flatgeobuf_agg_ctx *ctx)
static void ensure_properties_size(struct flatgeobuf_agg_ctx *ctx, size_t size)
struct flatgeobuf_agg_ctx * flatgeobuf_agg_ctx_init(const char *geom_name, const bool create_index)
Initialize aggregation context.
void flatgeobuf_agg_transfn(struct flatgeobuf_agg_ctx *ctx)
Aggregation step.
static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values, bool *isnull)
void flatgeobuf_decode_row(struct flatgeobuf_decode_ctx *ctx)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
void * lwalloc(size_t size)