PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ composite_to_geojson()

static void composite_to_geojson ( FunctionCallInfo  fcinfo,
Datum  composite,
char *  geom_column_name,
char *  id_column_name,
int32  maxdecimaldigits,
StringInfo  result,
bool  use_line_feeds,
Oid  geom_oid,
Oid  geog_oid 
)
static

Definition at line 126 of file lwgeom_out_geojson.c.

135{
136 HeapTupleHeader td;
137 Oid tupType;
138 int32 tupTypmod;
139 TupleDesc tupdesc;
140 HeapTupleData tmptup, *tuple;
141 int i;
142 bool needsep = false;
143 const char *sep;
144 StringInfo props = makeStringInfo();
145 StringInfo id = makeStringInfo();
146 bool geom_column_found = false;
147 bool id_column_found = false;
148 HTAB *prop_keys = NULL;
149 HASHCTL ctl;
150
151 MemSet(&ctl, 0, sizeof(ctl));
152 ctl.keysize = NAMEDATALEN;
153 ctl.entrysize = sizeof(GeoJsonPropKey);
154 ctl.hcxt = CurrentMemoryContext;
155
156 sep = use_line_feeds ? ",\n " : ", ";
157
158 td = DatumGetHeapTupleHeader(composite);
159
160 /* Extract rowtype info and find a tupdesc */
161 tupType = HeapTupleHeaderGetTypeId(td);
162 tupTypmod = HeapTupleHeaderGetTypMod(td);
163 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
164
165 /*
166 * Keep track of property names for this feature so that we can warn
167 * when SQL supplies duplicate aliases. GeoJSON accepts repeated keys,
168 * yet downstream PostgreSQL jsonb casts retain only the last value, so
169 * surfacing the issue here prevents silent information loss.
170 */
171 prop_keys =
172#if POSTGIS_PGSQL_VERSION <= 130
173 hash_create("GeoJSON property keys", Max(tupdesc->natts, 8), &ctl, HASH_ELEM | HASH_CONTEXT);
174#else
175 hash_create("GeoJSON property keys", Max(tupdesc->natts, 8), &ctl, HASH_ELEM | HASH_CONTEXT | HASH_STRINGS);
176#endif
177
178 /* Build a temporary HeapTuple control structure */
179 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
180 tmptup.t_data = td;
181 tuple = &tmptup;
182
183 appendStringInfoString(result, "{\"type\": \"Feature\", \"geometry\": ");
184
185 for (i = 0; i < tupdesc->natts; i++)
186 {
187 Datum val;
188 bool isnull;
189 char *attname;
190 JsonTypeCategory tcategory;
191 Oid outfuncoid;
192 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
193 bool is_geom_column = false;
194 bool is_id_column = false;
195
196 if (att->attisdropped)
197 continue;
198
199 attname = NameStr(att->attname);
200 /* Use the column name if provided, use the first geometry column otherwise */
201 if (geom_column_name)
202 is_geom_column = (strcmp(attname, geom_column_name) == 0);
203 else
204 is_geom_column = (att->atttypid == geom_oid || att->atttypid == geog_oid);
205
206 if (id_column_name)
207 is_id_column = (strcmp(attname, id_column_name) == 0);
208
209 if ((!geom_column_found) && is_geom_column)
210 {
211 /* this is our geom column */
212 geom_column_found = true;
213
214 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
215 if (!isnull)
216 {
217 appendStringInfo(
218 result,
219 "%s",
220 TextDatumGetCString(CallerFInfoFunctionCall2(LWGEOM_asGeoJson,
221 fcinfo->flinfo,
222 InvalidOid,
223 val,
224 Int32GetDatum(maxdecimaldigits))));
225 }
226 else
227 {
228 appendStringInfoString(result, "null");
229 }
230 }
231 else if (is_id_column)
232 {
233 id_column_found = true;
234
235 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
236
237 if (isnull)
238 {
239 tcategory = JSONTYPE_NULL;
240 outfuncoid = InvalidOid;
241 }
242 else
243 json_categorize_type(att->atttypid, &tcategory, &outfuncoid);
244
245 datum_to_json(val, isnull, id, tcategory, outfuncoid, false);
246 }
247 else
248 {
249 bool found;
250
251 if (needsep)
252 appendStringInfoString(props, sep);
253 needsep = true;
254
255 (void)hash_search(prop_keys, attname, HASH_ENTER, &found);
256 if (found)
257 {
258 ereport(
259 WARNING,
260 (errmsg("duplicate key \"%s\" encountered while building GeoJSON properties",
261 attname),
262 errhint("Only the last value for each key is preserved when casting to JSONB.")));
263 }
264
265 escape_json(props, attname);
266 appendStringInfoString(props, ": ");
267
268 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
269
270 if (isnull)
271 {
272 tcategory = JSONTYPE_NULL;
273 outfuncoid = InvalidOid;
274 }
275 else
276 json_categorize_type(att->atttypid, &tcategory, &outfuncoid);
277
278 datum_to_json(val, isnull, props, tcategory, outfuncoid, false);
279 }
280 }
281
282 if (!geom_column_found)
283 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("geometry column is missing")));
284
285 if (id_column_name)
286 {
287 if (!id_column_found)
288 ereport(ERROR,
289 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
290 errmsg("Specified id column \"%s\" is missing", id_column_name)));
291
292 appendStringInfoString(result, ", \"id\": ");
293 appendStringInfo(result, "%s", id->data);
294 }
295
296 appendStringInfoString(result, ", \"properties\": {");
297 appendStringInfo(result, "%s", props->data);
298
299 appendStringInfoString(result, "}}");
300 hash_destroy(prop_keys);
301 ReleaseTupleDesc(tupdesc);
302}
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
static void json_categorize_type(Oid typoid, JsonTypeCategory *tcategory, Oid *outfuncoid)
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
JsonTypeCategory
@ JSONTYPE_NULL
static void datum_to_json(Datum val, bool is_null, StringInfo result, JsonTypeCategory tcategory, Oid outfuncoid, bool key_scalar)
unsigned int int32
Definition shpopen.c:54

References datum_to_json(), json_categorize_type(), JSONTYPE_NULL, LWGEOM_asGeoJson(), and result.

Referenced by ST_AsGeoJsonRow().

Here is the call graph for this function:
Here is the caller graph for this function: