@@ -175,6 +175,7 @@ static int extract_variadic_args_min(FunctionCallInfo fcinfo,
175
175
int min_num_args );
176
176
static agtype_value * agtype_build_map_as_agtype_value (FunctionCallInfo fcinfo );
177
177
agtype_value * agtype_composite_to_agtype_value_binary (agtype * a );
178
+ static agtype_value * tostring_helper (Datum arg , Oid type , char * msghdr );
178
179
179
180
/* global storage of OID for agtype and _agtype */
180
181
static Oid g_AGTYPEOID = InvalidOid ;
@@ -2378,6 +2379,7 @@ static agtype_value *agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo)
2378
2379
result .res = push_agtype_value (& result .parse_state , WAGT_BEGIN_OBJECT ,
2379
2380
NULL );
2380
2381
2382
+ /* iterate through the arguments and build the object */
2381
2383
for (i = 0 ; i < nargs ; i += 2 )
2382
2384
{
2383
2385
/* process key */
@@ -2388,7 +2390,25 @@ static agtype_value *agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo)
2388
2390
errmsg ("argument %d: key must not be null" , i + 1 )));
2389
2391
}
2390
2392
2391
- add_agtype (args [i ], false, & result , types [i ], true);
2393
+ /*
2394
+ * If the key is agtype, we need to extract it as an agtype string and
2395
+ * push the value.
2396
+ */
2397
+ if (types [i ] == AGTYPEOID )
2398
+ {
2399
+ agtype_value * agtv = NULL ;
2400
+
2401
+ agtv = tostring_helper (args [i ], types [i ],
2402
+ "agtype_build_map_as_agtype_value" );
2403
+ result .res = push_agtype_value (& result .parse_state , WAGT_KEY , agtv );
2404
+
2405
+ /* free the agtype_value from tostring_helper */
2406
+ pfree (agtv );
2407
+ }
2408
+ else
2409
+ {
2410
+ add_agtype (args [i ], false, & result , types [i ], true);
2411
+ }
2392
2412
2393
2413
/* process value */
2394
2414
add_agtype (args [i + 1 ], nulls [i + 1 ], & result , types [i + 1 ], false);
@@ -6709,16 +6729,12 @@ PG_FUNCTION_INFO_V1(age_tostring);
6709
6729
Datum age_tostring (PG_FUNCTION_ARGS )
6710
6730
{
6711
6731
int nargs ;
6712
- Datum * args ;
6713
6732
Datum arg ;
6714
- bool * nulls ;
6715
- Oid * types ;
6716
- agtype_value agtv_result ;
6717
- char * string = NULL ;
6718
- Oid type ;
6733
+ Oid type = InvalidOid ;
6734
+ agtype * agt = NULL ;
6735
+ agtype_value * agtv = NULL ;
6719
6736
6720
- /* extract argument values */
6721
- nargs = extract_variadic_args (fcinfo , 0 , true, & args , & types , & nulls );
6737
+ nargs = PG_NARGS ();
6722
6738
6723
6739
/* check number of args */
6724
6740
if (nargs > 1 )
@@ -6728,19 +6744,70 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6728
6744
}
6729
6745
6730
6746
/* check for null */
6731
- if (nargs < 0 || nulls [ 0 ] )
6747
+ if (nargs < 1 || PG_ARGISNULL ( 0 ) )
6732
6748
{
6733
6749
PG_RETURN_NULL ();
6734
6750
}
6735
6751
6752
+ /* get the argument and type */
6753
+ arg = PG_GETARG_DATUM (0 );
6754
+ type = get_fn_expr_argtype (fcinfo -> flinfo , 0 );
6755
+
6756
+ /* verify that if the type is UNKNOWNOID it can be converted */
6757
+ if (type == UNKNOWNOID && !get_fn_expr_arg_stable (fcinfo -> flinfo , 0 ))
6758
+ {
6759
+ ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6760
+ errmsg ("toString() UNKNOWNOID and not stable" )));
6761
+ }
6762
+
6736
6763
/*
6737
6764
* toString() supports integer, float, numeric, text, cstring, boolean,
6738
6765
* regtype or the agtypes: integer, float, numeric, string, boolean input
6739
6766
*/
6740
- arg = args [0 ];
6741
- type = types [0 ];
6767
+ agtv = tostring_helper (arg , type , "toString()" );
6742
6768
6743
- if (type != AGTYPEOID )
6769
+ /* if we get a NULL back we need to return NULL */
6770
+ if (agtv == NULL )
6771
+ {
6772
+ PG_RETURN_NULL ();
6773
+ }
6774
+
6775
+ /* convert to agtype and free the agtype_value */
6776
+ agt = agtype_value_to_agtype (agtv );
6777
+ pfree (agtv );
6778
+
6779
+ PG_RETURN_POINTER (agt );
6780
+ }
6781
+
6782
+ /*
6783
+ * Helper function to take any valid type and convert it to an agtype string.
6784
+ * Returns NULL for NULL output.
6785
+ */
6786
+ static agtype_value * tostring_helper (Datum arg , Oid type , char * msghdr )
6787
+ {
6788
+ agtype_value * agtv_result = NULL ;
6789
+ char * string = NULL ;
6790
+
6791
+ agtv_result = palloc0 (sizeof (agtype_value ));
6792
+
6793
+ /*
6794
+ * toString() supports: unknown, integer, float, numeric, text, cstring,
6795
+ * boolean, regtype or the agtypes: integer, float, numeric, string, and
6796
+ * boolean input.
6797
+ */
6798
+
6799
+ /*
6800
+ * If the type is UNKNOWNOID convert it to a cstring. Prior to passing an
6801
+ * UNKNOWNOID it should be verified to be stable.
6802
+ */
6803
+ if (type == UNKNOWNOID )
6804
+ {
6805
+ char * str = DatumGetPointer (arg );
6806
+
6807
+ string = pnstrdup (str , strlen (str ));
6808
+ }
6809
+ /* if it is not an AGTYPEOID */
6810
+ else if (type != AGTYPEOID )
6744
6811
{
6745
6812
if (type == INT2OID )
6746
6813
{
@@ -6787,11 +6854,12 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6787
6854
else
6788
6855
{
6789
6856
ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6790
- errmsg ("toString() unsupported argument type %d" ,
6791
- type )));
6857
+ errmsg ("%s unsupported argument type %d" ,
6858
+ msghdr , type )));
6792
6859
}
6793
6860
}
6794
- else
6861
+ /* if it is an AGTYPEOID */
6862
+ else if (type == AGTYPEOID )
6795
6863
{
6796
6864
agtype * agt_arg ;
6797
6865
agtype_value * agtv_value ;
@@ -6802,14 +6870,15 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6802
6870
if (!AGT_ROOT_IS_SCALAR (agt_arg ))
6803
6871
{
6804
6872
ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6805
- errmsg ("toString() only supports scalar arguments" )));
6873
+ errmsg ("%s only supports scalar arguments" ,
6874
+ msghdr )));
6806
6875
}
6807
6876
6808
6877
agtv_value = get_ith_agtype_value_from_container (& agt_arg -> root , 0 );
6809
6878
6810
6879
if (agtv_value -> type == AGTV_NULL )
6811
6880
{
6812
- PG_RETURN_NULL () ;
6881
+ return NULL ;
6813
6882
}
6814
6883
else if (agtv_value -> type == AGTV_INTEGER )
6815
6884
{
@@ -6838,17 +6907,24 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6838
6907
else
6839
6908
{
6840
6909
ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6841
- errmsg ("toString() unsupported argument agtype %d" ,
6842
- agtv_value -> type )));
6910
+ errmsg ("%s unsupported argument agtype %d" ,
6911
+ msghdr , agtv_value -> type )));
6843
6912
}
6844
6913
}
6914
+ /* it is an unknown type */
6915
+ else
6916
+ {
6917
+ ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6918
+ errmsg ("%s unknown argument agtype %d" ,
6919
+ msghdr , type )));
6920
+ }
6845
6921
6846
6922
/* build the result */
6847
- agtv_result . type = AGTV_STRING ;
6848
- agtv_result . val .string .val = string ;
6849
- agtv_result . val .string .len = strlen (string );
6923
+ agtv_result -> type = AGTV_STRING ;
6924
+ agtv_result -> val .string .val = string ;
6925
+ agtv_result -> val .string .len = strlen (string );
6850
6926
6851
- PG_RETURN_POINTER ( agtype_value_to_agtype ( & agtv_result )) ;
6927
+ return agtv_result ;
6852
6928
}
6853
6929
6854
6930
PG_FUNCTION_INFO_V1 (age_tostringlist );
0 commit comments