PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_in_flatgeobuf.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright (C) 2021 Björn Harrtell <bjorn@wololo.org>
22 *
23 **********************************************************************/
24
25
26#include <assert.h>
27
28#include "postgres.h"
29
30#include "../postgis_config.h"
31#include "lwgeom_pg.h"
32#include "liblwgeom.h"
33#include "lwgeom_cache.h"
34#include "funcapi.h"
35#include <executor/spi.h>
36#include <utils/builtins.h>
37#include "flatgeobuf.h"
38
39static char *get_pgtype(uint8_t column_type) {
40 switch (column_type) {
41 case flatgeobuf_column_type_bool:
42 return "boolean";
43 case flatgeobuf_column_type_byte:
44 case flatgeobuf_column_type_ubyte:
45 return "smallint";
46 case flatgeobuf_column_type_short:
47 return "smallint";
48 case flatgeobuf_column_type_int:
49 return "integer";
50 case flatgeobuf_column_type_uint:
51 case flatgeobuf_column_type_long:
52 case flatgeobuf_column_type_ulong:
53 return "bigint";
54 case flatgeobuf_column_type_float:
55 return "real";
56 case flatgeobuf_column_type_double:
57 return "double precision";
58 case flatgeobuf_column_type_datetime:
59 return "timestamptz";
60 case flatgeobuf_column_type_string:
61 return "text";
62 case flatgeobuf_column_type_binary:
63 return "bytea";
64 case flatgeobuf_column_type_json:
65 return "jsonb";
66 }
67 elog(ERROR, "unknown column_type %d", column_type);
68}
69
71Datum pgis_tablefromflatgeobuf(PG_FUNCTION_ARGS)
72{
74 text *schema_input;
75 char *schema;
76 text *table_input;
77 char *table;
78 char *format;
79 char *sql;
80 bytea *data;
81 uint16_t i;
82 char **column_defs;
83 size_t column_defs_total_len;
84 char *column_defs_str;
85
86 if (PG_ARGISNULL(0))
87 PG_RETURN_NULL();
88 if (PG_ARGISNULL(1))
89 PG_RETURN_NULL();
90
91 schema_input = PG_GETARG_TEXT_P(0);
92 schema = text_to_cstring(schema_input);
93
94 table_input = PG_GETARG_TEXT_P(1);
95 table = text_to_cstring(table_input);
96
97 data = PG_GETARG_BYTEA_PP(2);
98
99 ctx = palloc0(sizeof(*ctx));
100 ctx->ctx = palloc0(sizeof(flatgeobuf_ctx));
101 ctx->ctx->size = VARSIZE_ANY_EXHDR(data);
102 POSTGIS_DEBUGF(3, "bytea data size is %lld", ctx->ctx->size);
103 ctx->ctx->buf = lwalloc(ctx->ctx->size);
104 memcpy(ctx->ctx->buf, VARDATA_ANY(data), ctx->ctx->size);
105 ctx->ctx->offset = 0;
106
108 flatgeobuf_decode_header(ctx->ctx);
109
110 column_defs = palloc(sizeof(char *) * ctx->ctx->columns_size);
111 column_defs_total_len = 0;
112 POSTGIS_DEBUGF(2, "found %d columns", ctx->ctx->columns_size);
113 for (i = 0; i < ctx->ctx->columns_size; i++) {
114 flatgeobuf_column *column = ctx->ctx->columns[i];
115 const char *name = column->name;
116 uint8_t column_type = column->type;
117 char *pgtype = get_pgtype(column_type);
118 size_t len = strlen(name) + 1 + strlen(pgtype) + 1;
119 column_defs[i] = palloc0(sizeof(char) * len);
120 strcat(column_defs[i], name);
121 strcat(column_defs[i], " ");
122 strcat(column_defs[i], pgtype);
123 column_defs_total_len += len;
124 }
125 column_defs_str = palloc0(sizeof(char) * column_defs_total_len + (ctx->ctx->columns_size * 2) + 2 + 1);
126 if (ctx->ctx->columns_size > 0)
127 strcat(column_defs_str, ", ");
128 for (i = 0; i < ctx->ctx->columns_size; i++) {
129 strcat(column_defs_str, column_defs[i]);
130 if (i < ctx->ctx->columns_size - 1)
131 strcat(column_defs_str, ", ");
132 }
133
134 POSTGIS_DEBUGF(2, "column_defs_str %s", column_defs_str);
135
136 format = "create table %s.%s (id int, geom geometry%s)";
137 sql = palloc0(strlen(format) + strlen(schema) + strlen(table) + strlen(column_defs_str) + 1);
138
139 sprintf(sql, format, schema, table, column_defs_str);
140
141 POSTGIS_DEBUGF(3, "sql: %s", sql);
142
143 if (SPI_connect() != SPI_OK_CONNECT)
144 elog(ERROR, "Failed to connect SPI");
145
146 if (SPI_execute(sql, false, 0) != SPI_OK_UTILITY)
147 elog(ERROR, "Failed to create table");
148
149 if (SPI_finish() != SPI_OK_FINISH)
150 elog(ERROR, "Failed to finish SPI");
151
152 POSTGIS_DEBUG(3, "finished");
153
154 PG_RETURN_NULL();
155}
156
157// https://stackoverflow.com/questions/11740256/refactor-a-pl-pgsql-function-to-return-the-output-of-various-select-queries
159Datum pgis_fromflatgeobuf(PG_FUNCTION_ARGS)
160{
161 FuncCallContext *funcctx;
162
163 TupleDesc tupdesc;
164 bytea *data;
165 MemoryContext oldcontext;
166
168
169 if (SRF_IS_FIRSTCALL()) {
170 funcctx = SRF_FIRSTCALL_INIT();
171 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
172
173 funcctx->max_calls = 0;
174
175 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
176 ereport(ERROR,
177 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
178 errmsg("first argument of function must be composite type")));
179
180 data = PG_GETARG_BYTEA_PP(1);
181
182 ctx = palloc0(sizeof(*ctx));
183 ctx->tupdesc = tupdesc;
184 ctx->ctx = palloc0(sizeof(flatgeobuf_ctx));
185 ctx->ctx->size = VARSIZE_ANY_EXHDR(data);
186 POSTGIS_DEBUGF(3, "VARSIZE_ANY_EXHDR %lld", ctx->ctx->size);
187 ctx->ctx->buf = palloc(ctx->ctx->size);
188 memcpy(ctx->ctx->buf, VARDATA_ANY(data), ctx->ctx->size);
189 ctx->ctx->offset = 0;
190 ctx->done = false;
191 ctx->fid = 0;
192
193 funcctx->user_fctx = ctx;
194
195 if (ctx->ctx->size == 0) {
196 POSTGIS_DEBUG(2, "no data");
197 MemoryContextSwitchTo(oldcontext);
198 SRF_RETURN_DONE(funcctx);
199 }
200
202 flatgeobuf_decode_header(ctx->ctx);
203
204 POSTGIS_DEBUGF(2, "header decoded now at offset %lld", ctx->ctx->offset);
205
206 if (ctx->ctx->size == ctx->ctx->offset) {
207 POSTGIS_DEBUGF(2, "no feature data offset %lld", ctx->ctx->offset);
208 MemoryContextSwitchTo(oldcontext);
209 SRF_RETURN_DONE(funcctx);
210 }
211
212 // TODO: get table and verify structure against header
213 MemoryContextSwitchTo(oldcontext);
214 }
215
216 funcctx = SRF_PERCALL_SETUP();
217 ctx = funcctx->user_fctx;
218
219 if (!ctx->done) {
221 POSTGIS_DEBUG(2, "Calling SRF_RETURN_NEXT");
222 SRF_RETURN_NEXT(funcctx, ctx->result);
223 } else {
224 POSTGIS_DEBUG(2, "Calling SRF_RETURN_DONE");
225 SRF_RETURN_DONE(funcctx);
226 }
227}
void flatgeobuf_check_magicbytes(struct flatgeobuf_decode_ctx *ctx)
Definition flatgeobuf.c:268
void flatgeobuf_decode_row(struct flatgeobuf_decode_ctx *ctx)
Definition flatgeobuf.c:464
void * lwalloc(size_t size)
Definition lwutil.c:227
This library is the generic geometry handling section of PostGIS.
Datum pgis_fromflatgeobuf(PG_FUNCTION_ARGS)
static char * get_pgtype(uint8_t column_type)
PG_FUNCTION_INFO_V1(pgis_tablefromflatgeobuf)
Datum pgis_tablefromflatgeobuf(PG_FUNCTION_ARGS)
flatgeobuf_ctx * ctx
Definition flatgeobuf.h:62