94 Datum array = PG_GETARG_DATUM(0);
95 text *geom_column_text = PG_GETARG_TEXT_P(1);
96 char *geom_column = PG_ARGISNULL(1) ?
"" : text_to_cstring(geom_column_text);
97 int32 maxdecimaldigits = PG_GETARG_INT32(2);
98 bool do_pretty = PG_GETARG_BOOL(3);
99 text *id_column_text = PG_GETARG_TEXT_P(4);
100 char *id_column = PG_ARGISNULL(4) ?
"" : text_to_cstring(id_column_text);
102 Oid geom_oid = InvalidOid;
103 Oid geog_oid = InvalidOid;
106 postgis_initialize_cache();
107 geom_oid = postgis_oid(GEOMETRYOID);
108 geog_oid = postgis_oid(GEOGRAPHYOID);
110 if (strlen(geom_column) == 0)
112 if (strlen(id_column) == 0)
119 PG_RETURN_TEXT_P(cstring_to_text_with_len(
result.data,
result.len));
128 char *geom_column_name,
129 char *id_column_name,
130 int32 maxdecimaldigits,
140 HeapTupleData tmptup, *tuple;
142 bool needsep =
false;
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;
151 MemSet(&ctl, 0,
sizeof(ctl));
152 ctl.keysize = NAMEDATALEN;
154 ctl.hcxt = CurrentMemoryContext;
156 sep = use_line_feeds ?
",\n " :
", ";
158 td = DatumGetHeapTupleHeader(composite);
161 tupType = HeapTupleHeaderGetTypeId(td);
162 tupTypmod = HeapTupleHeaderGetTypMod(td);
163 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
172#if POSTGIS_PGSQL_VERSION <= 130
173 hash_create(
"GeoJSON property keys", Max(tupdesc->natts, 8), &ctl, HASH_ELEM | HASH_CONTEXT);
175 hash_create(
"GeoJSON property keys", Max(tupdesc->natts, 8), &ctl, HASH_ELEM | HASH_CONTEXT | HASH_STRINGS);
179 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
183 appendStringInfoString(
result,
"{\"type\": \"Feature\", \"geometry\": ");
185 for (i = 0; i < tupdesc->natts; i++)
192 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
193 bool is_geom_column =
false;
194 bool is_id_column =
false;
196 if (att->attisdropped)
199 attname = NameStr(att->attname);
201 if (geom_column_name)
202 is_geom_column = (strcmp(attname, geom_column_name) == 0);
204 is_geom_column = (att->atttypid == geom_oid || att->atttypid == geog_oid);
207 is_id_column = (strcmp(attname, id_column_name) == 0);
209 if ((!geom_column_found) && is_geom_column)
212 geom_column_found =
true;
214 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
224 Int32GetDatum(maxdecimaldigits))));
228 appendStringInfoString(
result,
"null");
231 else if (is_id_column)
233 id_column_found =
true;
235 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
240 outfuncoid = InvalidOid;
245 datum_to_json(val, isnull,
id, tcategory, outfuncoid,
false);
252 appendStringInfoString(props, sep);
255 (void)hash_search(prop_keys, attname, HASH_ENTER, &found);
260 (errmsg(
"duplicate key \"%s\" encountered while building GeoJSON properties",
262 errhint(
"Only the last value for each key is preserved when casting to JSONB.")));
265 escape_json(props, attname);
266 appendStringInfoString(props,
": ");
268 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
273 outfuncoid = InvalidOid;
278 datum_to_json(val, isnull, props, tcategory, outfuncoid,
false);
282 if (!geom_column_found)
283 ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg(
"geometry column is missing")));
287 if (!id_column_found)
289 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
290 errmsg(
"Specified id column \"%s\" is missing", id_column_name)));
292 appendStringInfoString(
result,
", \"id\": ");
293 appendStringInfo(
result,
"%s", id->data);
296 appendStringInfoString(
result,
", \"properties\": {");
297 appendStringInfo(
result,
"%s", props->data);
299 appendStringInfoString(
result,
"}}");
300 hash_destroy(prop_keys);
301 ReleaseTupleDesc(tupdesc);
327 typoid = getBaseType(typoid);
329 *outfuncoid = InvalidOid;
349 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
367 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
373 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
374 || typoid == RECORDARRAYOID)
376 else if (type_is_rowtype(typoid))
383 if (typoid >= FirstNormalObjectId)
386 CoercionPathType ctype;
388 ctype = find_coercion_pathway(JSONOID, typoid,
391 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
394 *outfuncoid = castfunc;
399 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
405 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
432 Assert(!(key_scalar && is_null));
436 appendStringInfoString(
result,
"null");
446 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
447 errmsg(
"key value must be scalar, not array, composite, or json")));
458 outputstr = DatumGetBool(val) ?
"true" :
"false";
460 escape_json(
result, outputstr);
462 appendStringInfoString(
result, outputstr);
465 outputstr = OidOutputFunctionCall(outfuncoid, val);
471 if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
472 appendStringInfoString(
result, outputstr);
474 escape_json(
result, outputstr);
479 char buf[MAXDATELEN + 1];
482 appendStringInfo(
result,
"\"%s\"", buf);
487 char buf[MAXDATELEN + 1];
490 appendStringInfo(
result,
"\"%s\"", buf);
495 char buf[MAXDATELEN + 1];
498 appendStringInfo(
result,
"\"%s\"", buf);
503 outputstr = OidOutputFunctionCall(outfuncoid, val);
504 appendStringInfoString(
result, outputstr);
509 jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val));
510 outputstr = text_to_cstring(jsontext);
511 appendStringInfoString(
result, outputstr);
516 outputstr = OidOutputFunctionCall(outfuncoid, val);
517 escape_json(
result, outputstr);
529 ArrayType *v = DatumGetArrayTypeP(array);
530 Oid element_type = ARR_ELEMTYPE(v);
545 nitems = ArrayGetNItems(ndim, dim);
549 appendStringInfoString(
result,
"[]");
553 get_typlenbyvalalign(element_type,
554 &typlen, &typbyval, &typalign);
557 &tcategory, &outfuncoid);
559 deconstruct_array(v, element_type, typlen, typbyval,
560 typalign, &elements, &nulls,
564 outfuncoid, use_line_feeds);
580 HeapTupleData tmptup,
583 bool needsep =
false;
586 sep = use_line_feeds ?
",\n " :
",";
588 td = DatumGetHeapTupleHeader(composite);
591 tupType = HeapTupleHeaderGetTypeId(td);
592 tupTypmod = HeapTupleHeaderGetTypMod(td);
593 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
596 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
600 appendStringInfoChar(
result,
'{');
602 for (i = 0; i < tupdesc->natts; i++)
609 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
611 if (att->attisdropped)
615 appendStringInfoString(
result, sep);
618 attname = NameStr(att->attname);
619 escape_json(
result, attname);
620 appendStringInfoChar(
result,
':');
622 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
627 outfuncoid = InvalidOid;
635 appendStringInfoChar(
result,
'}');
636 ReleaseTupleDesc(tupdesc);
647 Oid outfuncoid,
bool use_line_feeds)
654 sep = use_line_feeds ?
",\n " :
",";
656 appendStringInfoChar(
result,
'[');
658 for (i = 1; i <= dims[dim]; i++)
661 appendStringInfoString(
result, sep);
663 if (dim + 1 == ndims)
676 valcount, tcategory, outfuncoid,
false);
680 appendStringInfoChar(
result,
']');
718 buf = palloc(MAXDATELEN + 1);
727 date = DatumGetDateADT(value);
730 if (DATE_NOT_FINITE(date))
731 EncodeSpecialDate(date, buf);
734 j2date(date + POSTGRES_EPOCH_JDATE,
735 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
736 EncodeDateOnly(&tm, USE_XSD_DATES, buf);
742 TimeADT time = DatumGetTimeADT(value);
749 EncodeTimeOnly(tm, fsec,
false, 0, USE_XSD_DATES, buf);
754 TimeTzADT *time = DatumGetTimeTzADTP(value);
762 EncodeTimeOnly(tm, fsec,
true, tz, USE_XSD_DATES, buf);
771 timestamp = DatumGetTimestamp(value);
773 if (TIMESTAMP_NOT_FINITE(timestamp))
774 EncodeSpecialTimestamp(timestamp, buf);
775 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
776 EncodeDateTime(&tm, fsec,
false, 0, NULL, USE_XSD_DATES, buf);
779 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
780 errmsg(
"timestamp out of range")));
785 TimestampTz timestamp;
789 const char *tzn = NULL;
791 timestamp = DatumGetTimestampTz(value);
793 if (TIMESTAMP_NOT_FINITE(timestamp))
794 EncodeSpecialTimestamp(timestamp, buf);
795 else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
796 EncodeDateTime(&tm, fsec,
true, tz, tzn, USE_XSD_DATES, buf);
799 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
800 errmsg(
"timestamp out of range")));
804 elog(ERROR,
"unknown jsonb value datetime type oid %d", typid);
static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals, bool *nulls, int *valcount, JsonTypeCategory tcategory, Oid outfuncoid, bool use_line_feeds)
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)