144 HeapTupleData tmptup, *tuple;
146 bool needsep =
false;
148 StringInfo props = makeStringInfo();
149 StringInfo
id = makeStringInfo();
150 bool geom_column_found =
false;
151 bool id_column_found =
false;
152 HTAB *prop_keys = NULL;
155 MemSet(&ctl, 0,
sizeof(ctl));
156 ctl.keysize = NAMEDATALEN;
158 ctl.hcxt = CurrentMemoryContext;
160 sep = use_line_feeds ?
",\n " :
", ";
162 td = DatumGetHeapTupleHeader(composite);
165 tupType = HeapTupleHeaderGetTypeId(td);
166 tupTypmod = HeapTupleHeaderGetTypMod(td);
167 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
176 #if POSTGIS_PGSQL_VERSION <= 130
177 hash_create(
"GeoJSON property keys", Max(tupdesc->natts, 8), &ctl, HASH_ELEM | HASH_CONTEXT);
179 hash_create(
"GeoJSON property keys", Max(tupdesc->natts, 8), &ctl, HASH_ELEM | HASH_CONTEXT | HASH_STRINGS);
183 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
187 appendStringInfoString(
result,
"{\"type\": \"Feature\", \"geometry\": ");
189 for (i = 0; i < tupdesc->natts; i++)
196 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
197 bool is_geom_column =
false;
198 bool is_id_column =
false;
200 if (att->attisdropped)
203 attname = NameStr(att->attname);
205 if (geom_column_name)
206 is_geom_column = (strcmp(attname, geom_column_name) == 0);
208 is_geom_column = (att->atttypid == geom_oid || att->atttypid == geog_oid);
211 is_id_column = (strcmp(attname, id_column_name) == 0);
213 if ((!geom_column_found) && is_geom_column)
216 geom_column_found =
true;
218 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
228 Int32GetDatum(maxdecimaldigits))));
232 appendStringInfoString(
result,
"null");
235 else if (is_id_column)
237 id_column_found =
true;
239 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
244 outfuncoid = InvalidOid;
249 datum_to_json(val, isnull,
id, tcategory, outfuncoid,
false);
256 appendStringInfoString(props, sep);
259 (void)hash_search(prop_keys, attname, HASH_ENTER, &found);
264 (errmsg(
"duplicate key \"%s\" encountered while building GeoJSON properties",
266 errhint(
"Only the last value for each key is preserved when casting to JSONB.")));
269 escape_json(props, attname);
270 appendStringInfoString(props,
": ");
272 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
277 outfuncoid = InvalidOid;
282 datum_to_json(val, isnull, props, tcategory, outfuncoid,
false);
286 if (!geom_column_found)
287 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg(
"geometry column is missing")));
291 if (!id_column_found)
293 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
294 errmsg(
"Specified id column \"%s\" is missing", id_column_name)));
296 appendStringInfoString(
result,
", \"id\": ");
297 appendStringInfo(
result,
"%s", id->data);
300 appendStringInfoString(
result,
", \"properties\": {");
301 appendStringInfo(
result,
"%s", props->data);
303 appendStringInfoString(
result,
"}}");
304 hash_destroy(prop_keys);
305 ReleaseTupleDesc(tupdesc);
char result[OUT_DOUBLE_BUFFER_SIZE]
struct GeoJsonPropKey GeoJsonPropKey
static void json_categorize_type(Oid typoid, JsonTypeCategory *tcategory, Oid *outfuncoid)
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
static void datum_to_json(Datum val, bool is_null, StringInfo result, JsonTypeCategory tcategory, Oid outfuncoid, bool key_scalar)