@@ -396,6 +396,53 @@ byteasend(PG_FUNCTION_ARGS)
396
396
PG_RETURN_BYTEA_P (vlena );
397
397
}
398
398
399
+ Datum
400
+ bytea_agg_transfn (PG_FUNCTION_ARGS )
401
+ {
402
+ StringInfo state ;
403
+
404
+ state = PG_ARGISNULL (0 ) ?NULL : (StringInfo )PG_GETARG_POINTER (0 );
405
+
406
+ /* Append the value unless null. */
407
+ if (!PG_ARGISNULL (1 ))
408
+ {
409
+ bytea * value = PG_GETARG_BYTEA_PP (1 );
410
+
411
+ if (state == NULL )
412
+ state = makeStringAggState (fcinfo );
413
+
414
+ appendBinaryStringInfo (state ,VARDATA_ANY (value ),VARSIZE_ANY_EXHDR (value ));
415
+ }
416
+
417
+ /*
418
+ * The transition type for bytea_agg() is declared to be "internal",
419
+ * which is a pass-by-value type the same size as a pointer.
420
+ */
421
+ PG_RETURN_POINTER (state );
422
+ }
423
+
424
+ Datum
425
+ bytea_agg_finalfn (PG_FUNCTION_ARGS )
426
+ {
427
+ StringInfo state ;
428
+
429
+ /* cannot be called directly because of internal-type argument */
430
+ Assert (AggCheckCallContext (fcinfo ,NULL ));
431
+
432
+ state = PG_ARGISNULL (0 ) ?NULL : (StringInfo )PG_GETARG_POINTER (0 );
433
+
434
+ if (state != NULL )
435
+ {
436
+ bytea * result ;
437
+
438
+ result = (bytea * )palloc (state -> len + VARHDRSZ );
439
+ SET_VARSIZE (result ,state -> len + VARHDRSZ );
440
+ memcpy (VARDATA (result ),state -> data ,state -> len );
441
+ PG_RETURN_BYTEA_P (result );
442
+ }
443
+ else
444
+ PG_RETURN_NULL ();
445
+ }
399
446
400
447
/*
401
448
*textin- converts "..." to internal representation