2 #include "../postgis_config.h"
8 #include "access/htup_details.h"
9 #include "access/transam.h"
10 #include "catalog/pg_type.h"
11 #include "executor/spi.h"
12 #include "lib/stringinfo.h"
13 #include "libpq/pqformat.h"
14 #include "mb/pg_wchar.h"
15 #include "parser/parse_coerce.h"
16 #include "utils/array.h"
17 #include "utils/builtins.h"
18 #include "utils/date.h"
19 #include "utils/datetime.h"
20 #include "utils/lsyscache.h"
21 #include "utils/json.h"
22 #if POSTGIS_PGSQL_VERSION < 130
23 #include "utils/jsonapi.h"
25 #include "common/jsonapi.h"
27 #include "utils/typcache.h"
28 #include "utils/syscache.h"
31 #include "lwgeom_pg.h"
35 #if POSTGIS_PGSQL_VERSION < 180
53 Datum *vals,
bool *nulls,
int *valcount,
60 char *geom_column_name,
61 int32 maxdecimaldigits,
71 #if POSTGIS_PGSQL_VERSION < 180
77 static int postgis_time2tm(TimeADT time,
struct pg_tm *tm, fsec_t *fsec);
78 static int postgis_timetz2tm(TimeTzADT *time,
struct pg_tm *tm, fsec_t *fsec,
int *tzp);
90 Datum array = PG_GETARG_DATUM(0);
91 text *geom_column_text = PG_GETARG_TEXT_P(1);
92 int32 maxdecimaldigits = PG_GETARG_INT32(2);
93 bool do_pretty = PG_GETARG_BOOL(3);
95 char *geom_column = text_to_cstring(geom_column_text);
96 Oid geom_oid = InvalidOid;
97 Oid geog_oid = InvalidOid;
100 postgis_initialize_cache();
101 geom_oid = postgis_oid(GEOMETRYOID);
102 geog_oid = postgis_oid(GEOGRAPHYOID);
104 if (strlen(geom_column) == 0)
107 result = makeStringInfo();
111 PG_RETURN_TEXT_P(cstring_to_text_with_len(
result->data,
result->len));
120 char *geom_column_name,
121 int32 maxdecimaldigits,
131 HeapTupleData tmptup,
134 bool needsep =
false;
136 StringInfo props = makeStringInfo();
137 bool geom_column_found =
false;
139 sep = use_line_feeds ?
",\n " :
", ";
141 td = DatumGetHeapTupleHeader(composite);
144 tupType = HeapTupleHeaderGetTypeId(td);
145 tupTypmod = HeapTupleHeaderGetTypMod(td);
146 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
149 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
153 appendStringInfoString(
result,
"{\"type\": \"Feature\", \"geometry\": ");
155 for (i = 0; i < tupdesc->natts; i++)
162 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
163 bool is_geom_column =
false;
165 if (att->attisdropped)
168 attname = NameStr(att->attname);
170 if (geom_column_name)
171 is_geom_column = (strcmp(attname, geom_column_name) == 0);
173 is_geom_column = (att->atttypid == geom_oid || att->atttypid == geog_oid);
175 if ((!geom_column_found) && is_geom_column)
178 geom_column_found =
true;
180 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
190 Int32GetDatum(maxdecimaldigits))));
194 appendStringInfoString(
result,
"{\"type\": null}");
200 appendStringInfoString(props, sep);
203 escape_json(props, attname);
204 appendStringInfoString(props,
": ");
206 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
211 outfuncoid = InvalidOid;
216 datum_to_json(val, isnull, props, tcategory, outfuncoid,
false);
220 if (!geom_column_found)
222 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
223 errmsg(
"geometry column is missing")));
225 appendStringInfoString(
result,
", \"properties\": {");
226 appendStringInfo(
result,
"%s", props->data);
228 appendStringInfoString(
result,
"}}");
229 ReleaseTupleDesc(tupdesc);
247 #if POSTGIS_PGSQL_VERSION < 180
256 typoid = getBaseType(typoid);
258 *outfuncoid = InvalidOid;
278 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
296 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
302 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
303 || typoid == RECORDARRAYOID)
305 else if (type_is_rowtype(typoid))
312 if (typoid >= FirstNormalObjectId)
315 CoercionPathType ctype;
317 ctype = find_coercion_pathway(JSONOID, typoid,
320 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
323 *outfuncoid = castfunc;
328 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
334 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
361 Assert(!(key_scalar && is_null));
365 appendStringInfoString(
result,
"null");
375 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
376 errmsg(
"key value must be scalar, not array, composite, or json")));
387 outputstr = DatumGetBool(val) ?
"true" :
"false";
389 escape_json(
result, outputstr);
391 appendStringInfoString(
result, outputstr);
394 outputstr = OidOutputFunctionCall(outfuncoid, val);
400 if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
401 appendStringInfoString(
result, outputstr);
403 escape_json(
result, outputstr);
408 char buf[MAXDATELEN + 1];
411 appendStringInfo(
result,
"\"%s\"", buf);
416 char buf[MAXDATELEN + 1];
419 appendStringInfo(
result,
"\"%s\"", buf);
424 char buf[MAXDATELEN + 1];
427 appendStringInfo(
result,
"\"%s\"", buf);
432 outputstr = OidOutputFunctionCall(outfuncoid, val);
433 appendStringInfoString(
result, outputstr);
438 jsontext = DatumGetTextPP(OidFunctionCall1(outfuncoid, val));
439 outputstr = text_to_cstring(jsontext);
440 appendStringInfoString(
result, outputstr);
445 outputstr = OidOutputFunctionCall(outfuncoid, val);
446 escape_json(
result, outputstr);
458 ArrayType *v = DatumGetArrayTypeP(array);
459 Oid element_type = ARR_ELEMTYPE(v);
474 nitems = ArrayGetNItems(ndim, dim);
478 appendStringInfoString(
result,
"[]");
482 get_typlenbyvalalign(element_type,
483 &typlen, &typbyval, &typalign);
486 &tcategory, &outfuncoid);
488 deconstruct_array(v, element_type, typlen, typbyval,
489 typalign, &elements, &nulls,
493 outfuncoid, use_line_feeds);
509 HeapTupleData tmptup,
512 bool needsep =
false;
515 sep = use_line_feeds ?
",\n " :
",";
517 td = DatumGetHeapTupleHeader(composite);
520 tupType = HeapTupleHeaderGetTypeId(td);
521 tupTypmod = HeapTupleHeaderGetTypMod(td);
522 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
525 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
529 appendStringInfoChar(
result,
'{');
531 for (i = 0; i < tupdesc->natts; i++)
538 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
540 if (att->attisdropped)
544 appendStringInfoString(
result, sep);
547 attname = NameStr(att->attname);
548 escape_json(
result, attname);
549 appendStringInfoChar(
result,
':');
551 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
556 outfuncoid = InvalidOid;
564 appendStringInfoChar(
result,
'}');
565 ReleaseTupleDesc(tupdesc);
576 Oid outfuncoid,
bool use_line_feeds)
583 sep = use_line_feeds ?
",\n " :
",";
585 appendStringInfoChar(
result,
'[');
587 for (i = 1; i <= dims[dim]; i++)
590 appendStringInfoString(
result, sep);
592 if (dim + 1 == ndims)
605 valcount, tcategory, outfuncoid,
false);
609 appendStringInfoChar(
result,
']');
615 tm->tm_hour = time / USECS_PER_HOUR;
616 time -= tm->tm_hour * USECS_PER_HOUR;
617 tm->tm_min = time / USECS_PER_MINUTE;
618 time -= tm->tm_min * USECS_PER_MINUTE;
619 tm->tm_sec = time / USECS_PER_SEC;
620 time -= tm->tm_sec * USECS_PER_SEC;
628 TimeOffset trem = time->time;
630 tm->tm_hour = trem / USECS_PER_HOUR;
631 trem -= tm->tm_hour * USECS_PER_HOUR;
632 tm->tm_min = trem / USECS_PER_MINUTE;
633 trem -= tm->tm_min * USECS_PER_MINUTE;
634 tm->tm_sec = trem / USECS_PER_SEC;
635 *fsec = trem - tm->tm_sec * USECS_PER_SEC;
647 buf = palloc(MAXDATELEN + 1);
656 date = DatumGetDateADT(
value);
659 if (DATE_NOT_FINITE(date))
660 EncodeSpecialDate(date, buf);
663 j2date(date + POSTGRES_EPOCH_JDATE,
664 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
665 EncodeDateOnly(&tm, USE_XSD_DATES, buf);
671 TimeADT time = DatumGetTimeADT(
value);
678 EncodeTimeOnly(tm, fsec,
false, 0, USE_XSD_DATES, buf);
683 TimeTzADT *time = DatumGetTimeTzADTP(
value);
691 EncodeTimeOnly(tm, fsec,
true, tz, USE_XSD_DATES, buf);
700 timestamp = DatumGetTimestamp(
value);
702 if (TIMESTAMP_NOT_FINITE(timestamp))
703 EncodeSpecialTimestamp(timestamp, buf);
704 else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
705 EncodeDateTime(&tm, fsec,
false, 0, NULL, USE_XSD_DATES, buf);
708 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
709 errmsg(
"timestamp out of range")));
714 TimestampTz timestamp;
718 const char *tzn = NULL;
720 timestamp = DatumGetTimestampTz(
value);
722 if (TIMESTAMP_NOT_FINITE(timestamp))
723 EncodeSpecialTimestamp(timestamp, buf);
724 else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
725 EncodeDateTime(&tm, fsec,
true, tz, tzn, USE_XSD_DATES, buf);
728 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
729 errmsg(
"timestamp out of range")));
733 elog(ERROR,
"unknown jsonb value datetime type oid %d", typid);
char result[OUT_DOUBLE_BUFFER_SIZE]
This library is the generic geometry handling section of PostGIS.
Datum row_to_geojson(PG_FUNCTION_ARGS)
static int postgis_timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
static int postgis_time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
static void json_categorize_type(Oid typoid, JsonTypeCategory *tcategory, Oid *outfuncoid)
PG_FUNCTION_INFO_V1(ST_AsGeoJsonRow)
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
static void composite_to_geojson(FunctionCallInfo fcinfo, 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)
Datum ST_AsGeoJsonRow(PG_FUNCTION_ARGS)
static char * postgis_JsonEncodeDateTime(char *buf, Datum value, Oid typid)
static void composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
static void array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
static void datum_to_json(Datum val, bool is_null, StringInfo result, JsonTypeCategory tcategory, Oid outfuncoid, bool key_scalar)