83 Datum array = PG_GETARG_DATUM(0);
84 text *geom_column_text = PG_GETARG_TEXT_P(1);
85 int32 maxdecimaldigits = PG_GETARG_INT32(2);
86 bool do_pretty = PG_GETARG_BOOL(3);
89 Oid geom_oid = InvalidOid;
90 Oid geog_oid = InvalidOid;
93 postgis_initialize_cache(fcinfo);
94 geom_oid = postgis_oid(GEOMETRYOID);
95 geog_oid = postgis_oid(GEOGRAPHYOID);
97 if (strlen(geom_column) == 0)
100 result = makeStringInfo();
102 composite_to_geojson(array, geom_column, maxdecimaldigits, result, do_pretty, geom_oid, geog_oid);
104 PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
112 StringInfo result,
bool use_line_feeds, Oid geom_oid, Oid geog_oid)
118 HeapTupleData tmptup,
121 bool needsep =
false;
123 StringInfo props = makeStringInfo();
124 bool geom_column_found =
false;
126 sep = use_line_feeds ?
",\n " :
", ";
128 td = DatumGetHeapTupleHeader(composite);
131 tupType = HeapTupleHeaderGetTypeId(td);
132 tupTypmod = HeapTupleHeaderGetTypMod(td);
133 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
136 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
140 appendStringInfoString(result,
"{\"type\": \"Feature\", \"geometry\": ");
142 for (i = 0; i < tupdesc->natts; i++)
149 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
150 bool is_geom_column =
false;
152 if (att->attisdropped)
155 attname = NameStr(att->attname);
157 if (geom_column_name)
158 is_geom_column = (strcmp(attname, geom_column_name) == 0);
160 is_geom_column = (att->atttypid == geom_oid || att->atttypid == geog_oid);
162 if ((!geom_column_found) && is_geom_column)
165 geom_column_found =
true;
167 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
170 appendStringInfo(result,
"%s",
171 TextDatumGetCString(DirectFunctionCall2(
LWGEOM_asGeoJson, val, Int32GetDatum(maxdecimaldigits))));
175 appendStringInfoString(result,
"{\"type\": null}");
181 appendStringInfoString(props, sep);
184 escape_json(props, attname);
185 appendStringInfoString(props,
": ");
187 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
192 outfuncoid = InvalidOid;
197 datum_to_json(val, isnull, props, tcategory, outfuncoid,
false);
201 if (!geom_column_found)
203 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
204 errmsg(
"geometry column is missing")));
206 appendStringInfoString(result,
", \"properties\": {");
207 appendStringInfo(result,
"%s", props->data);
209 appendStringInfoString(result,
"}}");
210 ReleaseTupleDesc(tupdesc);
235 typoid = getBaseType(typoid);
237 *outfuncoid = InvalidOid;
257 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
275 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
281 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
282 || typoid == RECORDARRAYOID)
284 else if (type_is_rowtype(typoid))
291 if (typoid >= FirstNormalObjectId)
294 CoercionPathType ctype;
296 ctype = find_coercion_pathway(JSONOID, typoid,
299 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
302 *outfuncoid = castfunc;
307 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
313 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
340 Assert(!(key_scalar && is_null));
344 appendStringInfoString(result,
"null");
354 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
355 errmsg(
"key value must be scalar, not array, composite, or json")));
366 outputstr = DatumGetBool(val) ?
"true" :
"false";
368 escape_json(result, outputstr);
370 appendStringInfoString(result, outputstr);
373 outputstr = OidOutputFunctionCall(outfuncoid, val);
379 if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
380 appendStringInfoString(result, outputstr);
382 escape_json(result, outputstr);
387 char buf[MAXDATELEN + 1];
390 appendStringInfo(result,
"\"%s\"", buf);
395 char buf[MAXDATELEN + 1];
398 appendStringInfo(result,
"\"%s\"", buf);
403 char buf[MAXDATELEN + 1];
406 appendStringInfo(result,
"\"%s\"", buf);
411 outputstr = OidOutputFunctionCall(outfuncoid, val);
412 appendStringInfoString(result, outputstr);
417 jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val));
419 appendStringInfoString(result, outputstr);
424 outputstr = OidOutputFunctionCall(outfuncoid, val);
425 escape_json(result, outputstr);
437 ArrayType *v = DatumGetArrayTypeP(array);
438 Oid element_type = ARR_ELEMTYPE(v);
453 nitems = ArrayGetNItems(ndim, dim);
457 appendStringInfoString(result,
"[]");
461 get_typlenbyvalalign(element_type,
462 &typlen, &typbyval, &typalign);
465 &tcategory, &outfuncoid);
467 deconstruct_array(v, element_type, typlen, typbyval,
468 typalign, &elements, &nulls,
472 outfuncoid, use_line_feeds);
488 HeapTupleData tmptup,
491 bool needsep =
false;
494 sep = use_line_feeds ?
",\n " :
",";
496 td = DatumGetHeapTupleHeader(composite);
499 tupType = HeapTupleHeaderGetTypeId(td);
500 tupTypmod = HeapTupleHeaderGetTypMod(td);
501 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
504 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
508 appendStringInfoChar(result,
'{');
510 for (i = 0; i < tupdesc->natts; i++)
517 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
519 if (att->attisdropped)
523 appendStringInfoString(result, sep);
526 attname = NameStr(att->attname);
527 escape_json(result, attname);
528 appendStringInfoChar(result,
':');
530 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
535 outfuncoid = InvalidOid;
540 datum_to_json(val, isnull, result, tcategory, outfuncoid,
false);
543 appendStringInfoChar(result,
'}');
544 ReleaseTupleDesc(tupdesc);
555 Oid outfuncoid,
bool use_line_feeds)
562 sep = use_line_feeds ?
",\n " :
",";
564 appendStringInfoChar(result,
'[');
566 for (i = 1; i <= dims[dim]; i++)
569 appendStringInfoString(result, sep);
571 if (dim + 1 == ndims)
573 datum_to_json(vals[*valcount], nulls[*valcount], result, tcategory,
584 valcount, tcategory, outfuncoid,
false);
588 appendStringInfoChar(result,
']');
594 tm->tm_hour = time / USECS_PER_HOUR;
595 time -= tm->tm_hour * USECS_PER_HOUR;
596 tm->tm_min = time / USECS_PER_MINUTE;
597 time -= tm->tm_min * USECS_PER_MINUTE;
598 tm->tm_sec = time / USECS_PER_SEC;
599 time -= tm->tm_sec * USECS_PER_SEC;
607 TimeOffset trem = time->time;
609 tm->tm_hour = trem / USECS_PER_HOUR;
610 trem -= tm->tm_hour * USECS_PER_HOUR;
611 tm->tm_min = trem / USECS_PER_MINUTE;
612 trem -= tm->tm_min * USECS_PER_MINUTE;
613 tm->tm_sec = trem / USECS_PER_SEC;
614 *fsec = trem - tm->tm_sec * USECS_PER_SEC;
626 buf = palloc(MAXDATELEN + 1);
635 date = DatumGetDateADT(value);
638 if (DATE_NOT_FINITE(date))
639 EncodeSpecialDate(date, buf);
642 j2date(date + POSTGRES_EPOCH_JDATE,
643 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
644 EncodeDateOnly(&tm, USE_XSD_DATES, buf);
650 TimeADT time = DatumGetTimeADT(value);
657 EncodeTimeOnly(tm, fsec,
false, 0, USE_XSD_DATES, buf);
662 TimeTzADT *time = DatumGetTimeTzADTP(value);
670 EncodeTimeOnly(tm, fsec,
true, tz, USE_XSD_DATES, buf);
679 timestamp = DatumGetTimestamp(value);
681 if (TIMESTAMP_NOT_FINITE(timestamp))
682 EncodeSpecialTimestamp(timestamp, buf);
683 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
684 EncodeDateTime(&tm, fsec,
false, 0, NULL, USE_XSD_DATES, buf);
687 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
688 errmsg(
"timestamp out of range")));
693 TimestampTz timestamp;
697 const char *tzn = NULL;
699 timestamp = DatumGetTimestampTz(value);
701 if (TIMESTAMP_NOT_FINITE(timestamp))
702 EncodeSpecialTimestamp(timestamp, buf);
703 else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
704 EncodeDateTime(&tm, fsec,
true, tz, tzn, USE_XSD_DATES, buf);
707 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
708 errmsg(
"timestamp out of range")));
712 elog(ERROR,
"unknown jsonb value datetime type oid %d", typid);
static void composite_to_geojson(Datum composite, char *geom_column_name, int32 maxdecimaldigits, StringInfo result, bool use_line_feeds, Oid geom_oid, Oid geog_oid)
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)
char * text_to_cstring(const text *textptr)