27 #include "pgsql_compat.h"
29 #include "parser/parse_type.h"
31 #include "utils/timestamp.h"
32 #include "miscadmin.h"
33 #include "utils/date.h"
34 #include "utils/datetime.h"
35 #include "utils/jsonb.h"
41 return flatgeobuf_column_type_bool;
43 return flatgeobuf_column_type_short;
45 return flatgeobuf_column_type_int;
47 return flatgeobuf_column_type_long;
49 return flatgeobuf_column_type_float;
51 return flatgeobuf_column_type_double;
54 return flatgeobuf_column_type_string;
56 return flatgeobuf_column_type_json;
58 return flatgeobuf_column_type_binary;
63 return flatgeobuf_column_type_datetime;
65 elog(ERROR,
"flatgeobuf: get_column_type: '%d' column type not supported",
72 flatgeobuf_column **columns;
73 uint32_t columns_size = 0;
74 Oid tupType = HeapTupleHeaderGetTypeId(ctx->
row);
75 int32 tupTypmod = HeapTupleHeaderGetTypMod(ctx->
row);
76 TupleDesc tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
77 int natts = tupdesc->natts;
78 bool geom_found =
false;
80 POSTGIS_DEBUG(2,
"calling inspect_table");
82 columns = palloc(
sizeof(flatgeobuf_column *) * natts);
87 for (
int i = 0; i < natts; i++) {
88 Oid typoid = getBaseType(TupleDescAttr(tupdesc, i)->atttypid);
89 const char *key = TupleDescAttr(tupdesc, i)->attname.data;
90 POSTGIS_DEBUGF(2,
"inspecting column definition for %s with oid %d", key, typoid);
92 if (!geom_found && typoid == postgis_oid(GEOMETRYOID)) {
98 if (!geom_found && strcmp(key, ctx->
geom_name) == 0) {
104 POSTGIS_DEBUGF(2,
"creating column definition for %s with oid %d", key, typoid);
106 c = (flatgeobuf_column *) palloc0(
sizeof(flatgeobuf_column));
107 c->name = pstrdup(key);
109 columns[columns_size] = c;
114 elog(ERROR,
"no geom column found");
116 if (columns_size > 0) {
117 ctx->
ctx->columns = columns;
118 ctx->
ctx->columns_size = columns_size;
125 if (ctx->
ctx->properties_size == 0) {
126 ctx->
ctx->properties_size = 1024 * 4;
127 POSTGIS_DEBUGF(2,
"flatgeobuf: properties buffer to size %d", ctx->
ctx->properties_size);
128 ctx->
ctx->properties = palloc(ctx->
ctx->properties_size);
130 if (ctx->
ctx->properties_size < size) {
131 ctx->
ctx->properties_size = ctx->
ctx->properties_size * 2;
132 POSTGIS_DEBUGF(2,
"flatgeobuf: reallocating properties buffer to size %d", ctx->
ctx->properties_size);
133 ctx->
ctx->properties = repalloc(ctx->
ctx->properties, ctx->
ctx->properties_size);
141 if (ctx->
ctx->features_count == 0) {
142 ctx->
ctx->items_len = 32;
143 ctx->
ctx->items = palloc(
sizeof(flatgeobuf_item *) * ctx->
ctx->items_len);
145 if (ctx->
ctx->items_len < (ctx->
ctx->features_count + 1)) {
146 ctx->
ctx->items_len = ctx->
ctx->items_len * 2;
147 POSTGIS_DEBUGF(2,
"flatgeobuf: reallocating items to len %ld", ctx->
ctx->items_len);
148 ctx->
ctx->items = repalloc(ctx->
ctx->items,
sizeof(flatgeobuf_item *) * ctx->
ctx->items_len);
173 for (i = 0; i < (uint32_t) ctx->
tupdesc->natts; i++) {
176 datum = GetAttributeByNum(ctx->
row, i + 1, &isnull);
180 memcpy(ctx->
ctx->properties + offset, &ci,
sizeof(ci));
181 offset +=
sizeof(ci);
182 typoid = getBaseType(TupleDescAttr(ctx->
tupdesc, i)->atttypid);
185 byte_value = DatumGetBool(datum) ? 1 : 0;
187 memcpy(ctx->
ctx->properties + offset, &byte_value,
sizeof(byte_value));
188 offset +=
sizeof(byte_value);
191 short_value = DatumGetInt16(datum);
193 memcpy(ctx->
ctx->properties + offset, &short_value,
sizeof(short_value));
194 offset +=
sizeof(short_value);
197 int_value = DatumGetInt32(datum);
199 memcpy(ctx->
ctx->properties + offset, &int_value,
sizeof(int_value));
200 offset +=
sizeof(int_value);
203 long_value = DatumGetInt64(datum);
205 memcpy(ctx->
ctx->properties + offset, &long_value,
sizeof(long_value));
206 offset +=
sizeof(long_value);
209 float_value = DatumGetFloat4(datum);
211 memcpy(ctx->
ctx->properties + offset, &float_value,
sizeof(float_value));
212 offset +=
sizeof(float_value);
215 double_value = DatumGetFloat8(datum);
217 memcpy(ctx->
ctx->properties + offset, &double_value,
sizeof(double_value));
218 offset +=
sizeof(double_value);
221 string_value = text_to_cstring(DatumGetTextP(datum));
222 len = strlen(string_value);
224 memcpy(ctx->
ctx->properties + offset, &len,
sizeof(len));
225 offset +=
sizeof(len);
227 memcpy(ctx->
ctx->properties + offset, string_value, len);
230 case TIMESTAMPTZOID: {
234 const char *tzn = NULL;
235 TimestampTz timestamp;
236 timestamp = DatumGetTimestampTz(datum);
237 timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL);
238 string_value = palloc(MAXDATELEN + 1);
239 EncodeDateTime(&tm, fsec,
true, tz, tzn, USE_ISO_DATES, string_value);
240 len = strlen(string_value);
242 memcpy(ctx->
ctx->properties + offset, &len,
sizeof(len));
243 offset +=
sizeof(len);
245 memcpy(ctx->
ctx->properties + offset, string_value, len);
264 POSTGIS_DEBUGF(3,
"offset %ld", offset);
265 ctx->
ctx->properties_len = offset;
271 uint8_t *buf = ctx->
ctx->buf + ctx->
ctx->offset;
274 for (i = 0; i < FLATGEOBUF_MAGICBYTES_SIZE / 2; i++)
275 if (buf[i] != flatgeobuf_magicbytes[i])
276 elog(ERROR,
"Data is not FlatGeobuf");
277 ctx->
ctx->offset += FLATGEOBUF_MAGICBYTES_SIZE;
283 flatgeobuf_column *column;
286 uint8_t *
data = ctx->
ctx->properties;
287 uint32_t size = ctx->
ctx->properties_len;
289 POSTGIS_DEBUGF(3,
"flatgeobuf: decode_properties from byte array with length %d at offset %d", size, offset);
293 if (size > 0 && size < (
sizeof(uint16_t) +
sizeof(uint8_t)))
294 elog(ERROR,
"flatgeobuf: decode_properties: Unexpected properties data size %d", size);
295 while (offset + 1 < size) {
296 if (offset +
sizeof(uint16_t) > size)
297 elog(ERROR,
"flatgeobuf: decode_properties: Unexpected offset %d", offset);
298 memcpy(&i,
data + offset,
sizeof(uint16_t));
300 offset +=
sizeof(uint16_t);
301 if (i >= ctx->
ctx->columns_size)
302 elog(ERROR,
"flatgeobuf: decode_properties: Column index %hu out of range", i);
303 column = ctx->
ctx->columns[i];
307 case flatgeobuf_column_type_bool: {
309 if (offset +
sizeof(uint8_t) > size)
310 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for bool value");
311 memcpy(&
value,
data + offset,
sizeof(uint8_t));
312 values[ci] = BoolGetDatum(
value);
313 offset +=
sizeof(uint8_t);
316 case flatgeobuf_column_type_byte: {
318 if (offset +
sizeof(int8_t) > size)
319 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for byte value");
320 memcpy(&
value,
data + offset,
sizeof(int8_t));
321 values[ci] = Int8GetDatum(
value);
322 offset +=
sizeof(int8_t);
325 case flatgeobuf_column_type_ubyte: {
327 if (offset +
sizeof(uint8_t) > size)
328 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for ubyte value");
329 memcpy(&
value,
data + offset,
sizeof(uint8_t));
330 values[ci] = UInt8GetDatum(
value);
331 offset +=
sizeof(uint8_t);
334 case flatgeobuf_column_type_short: {
336 if (offset +
sizeof(int16_t) > size)
337 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for short value");
338 memcpy(&
value,
data + offset,
sizeof(int16_t));
339 values[ci] = Int16GetDatum(
value);
340 offset +=
sizeof(int16_t);
343 case flatgeobuf_column_type_ushort: {
345 if (offset +
sizeof(uint16_t) > size)
346 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for ushort value");
347 memcpy(&
value,
data + offset,
sizeof(uint16_t));
348 values[ci] = UInt16GetDatum(
value);
349 offset +=
sizeof(uint16_t);
352 case flatgeobuf_column_type_int: {
354 if (offset +
sizeof(int32_t) > size)
355 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for int value");
356 memcpy(&
value,
data + offset,
sizeof(int32_t));
357 values[ci] = Int32GetDatum(
value);
358 offset +=
sizeof(int32_t);
361 case flatgeobuf_column_type_uint: {
363 if (offset +
sizeof(uint32_t) > size)
364 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for uint value");
365 memcpy(&
value,
data + offset,
sizeof(uint32_t));
366 values[ci] = UInt32GetDatum(
value);
367 offset +=
sizeof(uint32_t);
370 case flatgeobuf_column_type_long: {
372 if (offset +
sizeof(int64_t) > size)
373 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for long value");
374 memcpy(&
value,
data + offset,
sizeof(int64_t));
375 values[ci] = Int64GetDatum(
value);
376 offset +=
sizeof(int64_t);
379 case flatgeobuf_column_type_ulong: {
381 if (offset +
sizeof(uint64_t) > size)
382 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for ulong value");
383 memcpy(&
value,
data + offset,
sizeof(uint64_t));
384 values[ci] = UInt64GetDatum(
value);
385 offset +=
sizeof(uint64_t);
388 case flatgeobuf_column_type_float: {
390 if (offset +
sizeof(
float) > size)
391 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for float value");
392 memcpy(&
value,
data + offset,
sizeof(
float));
393 values[ci] = Float4GetDatum(
value);
394 offset +=
sizeof(float);
397 case flatgeobuf_column_type_double: {
399 if (offset +
sizeof(
double) > size)
400 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for double value");
401 memcpy(&
value,
data + offset,
sizeof(
double));
402 values[ci] = Float8GetDatum(
value);
403 offset +=
sizeof(double);
406 case flatgeobuf_column_type_string: {
408 if (offset +
sizeof(len) > size)
409 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for string value");
410 memcpy(&len,
data + offset,
sizeof(uint32_t));
411 offset +=
sizeof(len);
412 values[ci] = PointerGetDatum(cstring_to_text_with_len((
const char *)
data + offset, len));
416 case flatgeobuf_column_type_datetime: {
419 char workbuf[MAXDATELEN + MAXDATEFIELDS];
420 char *field[MAXDATEFIELDS];
421 int ftype[MAXDATEFIELDS];
424 struct pg_tm tt, *tm = &tt;
428 #if POSTGIS_PGSQL_VERSION >= 160
429 DateTimeErrorExtra extra;
431 if (offset +
sizeof(len) > size)
432 elog(ERROR,
"flatgeobuf: decode_properties: Invalid size for string value");
433 memcpy(&len,
data + offset,
sizeof(uint32_t));
434 offset +=
sizeof(len);
435 buf = palloc0(len + 1);
436 memcpy(buf, (
const char *)
data + offset, len);
437 ParseDateTime((
const char *) buf, workbuf,
sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf);
439 #if POSTGIS_PGSQL_VERSION >= 160
440 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp, &extra);
442 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
444 tm2timestamp(tm, fsec, &tzp, &dttz);
445 values[ci] = TimestampTzGetDatum(dttz);
459 elog(ERROR,
"flatgeobuf: decode_properties: Unknown type %d",
type);
468 uint32_t natts = ctx->
tupdesc->natts;
470 Datum *values = palloc0(natts *
sizeof(Datum *));
471 bool *isnull = palloc0(natts *
sizeof(
bool *));
473 values[0] = Int32GetDatum(ctx->
fid);
475 if (flatgeobuf_decode_feature(ctx->
ctx))
476 elog(ERROR,
"flatgeobuf_decode_feature: unsuccessful");
478 if (ctx->
ctx->lwgeom != NULL) {
479 values[1] = PointerGetDatum(geometry_serialize(ctx->
ctx->lwgeom));
481 POSTGIS_DEBUG(3,
"geometry is null");
485 if (natts > 2 && ctx->
ctx->properties_len > 0)
488 heapTuple = heap_form_tuple(ctx->
tupdesc, values, isnull);
489 ctx->
result = HeapTupleGetDatum(heapTuple);
492 POSTGIS_DEBUGF(3,
"fid now %d", ctx->
fid);
494 if (ctx->
ctx->offset == ctx->
ctx->size) {
495 POSTGIS_DEBUGF(3,
"reached end at %ld", ctx->
ctx->offset);
506 size_t size = VARHDRSZ + FLATGEOBUF_MAGICBYTES_SIZE;
507 ctx = palloc0(
sizeof(*
ctx));
508 ctx->ctx = palloc0(
sizeof(flatgeobuf_ctx));
510 memcpy(
ctx->ctx->buf + VARHDRSZ, flatgeobuf_magicbytes, FLATGEOBUF_MAGICBYTES_SIZE);
513 ctx->ctx->features_count = 0;
514 ctx->ctx->offset = size;
516 ctx->ctx->create_index = create_index;
534 if (
ctx->ctx->features_count == 0)
537 datum = GetAttributeByNum(
ctx->row,
ctx->geom_index + 1, &isnull);
542 ctx->ctx->lwgeom = lwgeom;
544 if (
ctx->ctx->features_count == 0)
545 flatgeobuf_encode_header(
ctx->ctx);
548 if (
ctx->ctx->create_index)
550 flatgeobuf_encode_feature(
ctx->ctx);
560 POSTGIS_DEBUGF(3,
"called at offset %ld",
ctx->ctx->offset);
564 if (
ctx->ctx->features_count == 0) {
565 flatgeobuf_encode_header(
ctx->ctx);
566 }
else if (
ctx->ctx->create_index) {
567 ctx->ctx->index_node_size = 16;
568 flatgeobuf_create_index(
ctx->ctx);
570 if (
ctx->tupdesc != NULL)
571 ReleaseTupleDesc(
ctx->tupdesc);
572 SET_VARSIZE(
ctx->ctx->buf,
ctx->ctx->offset);
573 POSTGIS_DEBUGF(3,
"returning at offset %ld",
ctx->ctx->offset);
574 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)