1. Andrew Dunstan
  2. pgdevel

Commits

Andrew Dunstan  committed 36debf0

working json_agg

  • Participants
  • Parent commits 1a95648

Comments (0)

Files changed (4)

File src/backend/utils/adt/json.c

View file
  • Ignore whitespace
 }
 
 /*
+ * json_agg transition function
+ */
+Datum
+json_agg_transfn(PG_FUNCTION_ARGS)
+{
+    Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
+    MemoryContext aggcontext, oldcontext;
+    StringInfo  state;
+    Datum       orig_val, val;
+	TYPCATEGORY tcategory;
+	Oid			typoutput;
+	bool		typisvarlena;
+
+    if (val_type == InvalidOid)
+        ereport(ERROR,
+                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                 errmsg("could not determine input data type")));
+
+    if (!AggCheckCallContext(fcinfo, &aggcontext))
+    {
+        /* cannot be called directly because of internal-type argument */
+        elog(ERROR, "json_agg_transfn called in non-aggregate context");
+    }
+
+    if (PG_ARGISNULL(0))
+	{
+		/* 
+		 * Make this StringInfo in a context where it will persist 
+		 * for the duration off the aggregate call. It's only needed
+		 * for this initial piece, as the StringInfo routines make sure
+		 * they use the right context to enlarge the object if necessary.
+		 */
+		oldcontext = MemoryContextSwitchTo(aggcontext);
+		state = makeStringInfo();
+		MemoryContextSwitchTo(oldcontext);
+
+		appendStringInfoChar(state,'[');
+	}
+	else
+	{
+		state =  (StringInfo) PG_GETARG_POINTER(0);
+		appendStringInfoString(state, ", ");
+	}
+
+	/* fast path for NULLs */
+    if (PG_ARGISNULL(1))
+	{
+		orig_val = (Datum) 0;
+		datum_to_json(orig_val, true, state, 0, InvalidOid);
+		PG_RETURN_POINTER(state);
+	}
+
+
+	orig_val = PG_GETARG_DATUM(1);
+
+	if (val_type == RECORDARRAYOID)
+		tcategory = TYPCATEGORY_ARRAY;
+	else if (val_type == RECORDOID)
+		tcategory = TYPCATEGORY_COMPOSITE;
+	else if (val_type == JSONOID)
+		tcategory = TYPCATEGORY_JSON;
+	else
+		tcategory = TypeCategory(val_type);
+	
+	getTypeOutputInfo(val_type, &typoutput, &typisvarlena);
+
+	/*
+	 * If we have a toasted datum, forcibly detoast it here to avoid
+	 * memory leakage inside the type's output routine.
+	 */
+	if (typisvarlena)
+		val = PointerGetDatum(PG_DETOAST_DATUM(orig_val));
+	else
+		val = orig_val;
+
+	if (! PG_ARGISNULL(0) && 
+		(tcategory == TYPCATEGORY_ARRAY || tcategory == TYPCATEGORY_COMPOSITE))
+	{
+		appendStringInfoString(state,"\n ");
+	}
+	
+	datum_to_json(val, false, state, tcategory, typoutput);
+
+	/* Clean up detoasted copy, if any */
+	if (val != orig_val)
+		pfree(DatumGetPointer(val));
+	
+    /*
+     * The transition type for array_agg() is declared to be "internal", which
+     * is a pass-by-value type the same size as a pointer.  So we can safely
+     * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
+     */
+    PG_RETURN_POINTER(state);
+}
+
+/*
+ * json_agg final function
+ */
+Datum
+json_agg_finalfn(PG_FUNCTION_ARGS)
+{
+    StringInfo  state;
+
+    Assert( ! PG_ARGISNULL(0));
+
+    /* cannot be called directly because of internal-type argument */
+    Assert(AggCheckCallContext(fcinfo, NULL));
+
+    state = (StringInfo) PG_GETARG_POINTER(0);
+
+	appendStringInfoChar(state,']');
+
+	PG_RETURN_TEXT_P(cstring_to_text(state->data));
+}
+
+/*
  * Produce a JSON string literal, properly escaping characters in the text.
  */
 void

File src/include/catalog/pg_aggregate.h

View file
  • Ignore whitespace
 /* bytea */
 DATA(insert ( 3545	bytea_string_agg_transfn	bytea_string_agg_finalfn		0	2281	_null_ ));
 
+/* json */
+DATA(insert ( 3172	json_agg_transfn	json_agg_finalfn		0	2281	_null_ ));
+
 /*
  * prototypes for functions in pg_aggregate.c
  */

File src/include/catalog/pg_proc.h

View file
  • Ignore whitespace
 DESCR("map row to json");
 DATA(insert OID = 3156 (  row_to_json	   PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 114 "2249 16" _null_ _null_ _null_ _null_ row_to_json_pretty _null_ _null_ _null_ ));
 DESCR("map row to json with optional pretty printing");
+DATA(insert OID = 3170 (  json_agg_transfn   PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 2283" _null_ _null_ _null_ _null_ json_agg_transfn _null_ _null_ _null_ ));
+DESCR("json aggregate transition function");
+DATA(insert OID = 3171 (  json_agg_finalfn   PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2277 "2281" _null_ _null_ _null_ _null_ json_agg_finalfn _null_ _null_ _null_ ));
+DESCR("json aggregate final function");
+DATA(insert OID = 3172 (  json_agg		   PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 114 "2283" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ ));
+DESCR("aggregate input into json");
 
 /* uuid */
 DATA(insert OID = 2952 (  uuid_in		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2950 "2275" _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ ));

File src/include/utils/json.h

View file
  • Ignore whitespace
 extern Datum array_to_json_pretty(PG_FUNCTION_ARGS);
 extern Datum row_to_json(PG_FUNCTION_ARGS);
 extern Datum row_to_json_pretty(PG_FUNCTION_ARGS);
+
+extern Datum json_agg_transfn(PG_FUNCTION_ARGS);
+extern Datum json_agg_finalfn(PG_FUNCTION_ARGS);
+
 extern void escape_json(StringInfo buf, const char *str);
 
 #endif   /* JSON_H */