@@ -174,6 +174,7 @@ static int extract_variadic_args_min(FunctionCallInfo fcinfo,
174
174
int min_num_args );
175
175
static agtype_value * agtype_build_map_as_agtype_value (FunctionCallInfo fcinfo );
176
176
agtype_value * agtype_composite_to_agtype_value_binary (agtype * a );
177
+ static agtype_value * tostring_helper (Datum arg , Oid type , char * msghdr );
177
178
178
179
/* global storage of OID for agtype and _agtype */
179
180
static Oid g_AGTYPEOID = InvalidOid ;
@@ -2377,6 +2378,7 @@ static agtype_value *agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo)
2377
2378
result .res = push_agtype_value (& result .parse_state , WAGT_BEGIN_OBJECT ,
2378
2379
NULL );
2379
2380
2381
+ /* iterate through the arguments and build the object */
2380
2382
for (i = 0 ; i < nargs ; i += 2 )
2381
2383
{
2382
2384
/* process key */
@@ -2387,7 +2389,25 @@ static agtype_value *agtype_build_map_as_agtype_value(FunctionCallInfo fcinfo)
2387
2389
errmsg ("argument %d: key must not be null" , i + 1 )));
2388
2390
}
2389
2391
2390
- add_agtype (args [i ], false, & result , types [i ], true);
2392
+ /*
2393
+ * If the key is agtype, we need to extract it as an agtype string and
2394
+ * push the value.
2395
+ */
2396
+ if (types [i ] == AGTYPEOID )
2397
+ {
2398
+ agtype_value * agtv = NULL ;
2399
+
2400
+ agtv = tostring_helper (args [i ], types [i ],
2401
+ "agtype_build_map_as_agtype_value" );
2402
+ result .res = push_agtype_value (& result .parse_state , WAGT_KEY , agtv );
2403
+
2404
+ /* free the agtype_value from tostring_helper */
2405
+ pfree (agtv );
2406
+ }
2407
+ else
2408
+ {
2409
+ add_agtype (args [i ], false, & result , types [i ], true);
2410
+ }
2391
2411
2392
2412
/* process value */
2393
2413
add_agtype (args [i + 1 ], nulls [i + 1 ], & result , types [i + 1 ], false);
@@ -6734,16 +6754,12 @@ PG_FUNCTION_INFO_V1(age_tostring);
6734
6754
Datum age_tostring (PG_FUNCTION_ARGS )
6735
6755
{
6736
6756
int nargs ;
6737
- Datum * args ;
6738
6757
Datum arg ;
6739
- bool * nulls ;
6740
- Oid * types ;
6741
- agtype_value agtv_result ;
6742
- char * string = NULL ;
6743
- Oid type ;
6758
+ Oid type = InvalidOid ;
6759
+ agtype * agt = NULL ;
6760
+ agtype_value * agtv = NULL ;
6744
6761
6745
- /* extract argument values */
6746
- nargs = extract_variadic_args (fcinfo , 0 , true, & args , & types , & nulls );
6762
+ nargs = PG_NARGS ();
6747
6763
6748
6764
/* check number of args */
6749
6765
if (nargs > 1 )
@@ -6753,19 +6769,70 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6753
6769
}
6754
6770
6755
6771
/* check for null */
6756
- if (nargs < 0 || nulls [ 0 ] )
6772
+ if (nargs < 1 || PG_ARGISNULL ( 0 ) )
6757
6773
{
6758
6774
PG_RETURN_NULL ();
6759
6775
}
6760
6776
6777
+ /* get the argument and type */
6778
+ arg = PG_GETARG_DATUM (0 );
6779
+ type = get_fn_expr_argtype (fcinfo -> flinfo , 0 );
6780
+
6781
+ /* verify that if the type is UNKNOWNOID it can be converted */
6782
+ if (type == UNKNOWNOID && !get_fn_expr_arg_stable (fcinfo -> flinfo , 0 ))
6783
+ {
6784
+ ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6785
+ errmsg ("toString() UNKNOWNOID and not stable" )));
6786
+ }
6787
+
6761
6788
/*
6762
6789
* toString() supports integer, float, numeric, text, cstring, boolean,
6763
6790
* regtype or the agtypes: integer, float, numeric, string, boolean input
6764
6791
*/
6765
- arg = args [0 ];
6766
- type = types [0 ];
6792
+ agtv = tostring_helper (arg , type , "toString()" );
6767
6793
6768
- if (type != AGTYPEOID )
6794
+ /* if we get a NULL back we need to return NULL */
6795
+ if (agtv == NULL )
6796
+ {
6797
+ PG_RETURN_NULL ();
6798
+ }
6799
+
6800
+ /* convert to agtype and free the agtype_value */
6801
+ agt = agtype_value_to_agtype (agtv );
6802
+ pfree (agtv );
6803
+
6804
+ PG_RETURN_POINTER (agt );
6805
+ }
6806
+
6807
+ /*
6808
+ * Helper function to take any valid type and convert it to an agtype string.
6809
+ * Returns NULL for NULL output.
6810
+ */
6811
+ static agtype_value * tostring_helper (Datum arg , Oid type , char * msghdr )
6812
+ {
6813
+ agtype_value * agtv_result = NULL ;
6814
+ char * string = NULL ;
6815
+
6816
+ agtv_result = palloc0 (sizeof (agtype_value ));
6817
+
6818
+ /*
6819
+ * toString() supports: unknown, integer, float, numeric, text, cstring,
6820
+ * boolean, regtype or the agtypes: integer, float, numeric, string, and
6821
+ * boolean input.
6822
+ */
6823
+
6824
+ /*
6825
+ * If the type is UNKNOWNOID convert it to a cstring. Prior to passing an
6826
+ * UNKNOWNOID it should be verified to be stable.
6827
+ */
6828
+ if (type == UNKNOWNOID )
6829
+ {
6830
+ char * str = DatumGetPointer (arg );
6831
+
6832
+ string = pnstrdup (str , strlen (str ));
6833
+ }
6834
+ /* if it is not an AGTYPEOID */
6835
+ else if (type != AGTYPEOID )
6769
6836
{
6770
6837
if (type == INT2OID )
6771
6838
{
@@ -6812,11 +6879,12 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6812
6879
else
6813
6880
{
6814
6881
ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6815
- errmsg ("toString() unsupported argument type %d" ,
6816
- type )));
6882
+ errmsg ("%s unsupported argument type %d" ,
6883
+ msghdr , type )));
6817
6884
}
6818
6885
}
6819
- else
6886
+ /* if it is an AGTYPEOID */
6887
+ else if (type == AGTYPEOID )
6820
6888
{
6821
6889
agtype * agt_arg ;
6822
6890
agtype_value * agtv_value ;
@@ -6827,14 +6895,15 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6827
6895
if (!AGT_ROOT_IS_SCALAR (agt_arg ))
6828
6896
{
6829
6897
ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6830
- errmsg ("toString() only supports scalar arguments" )));
6898
+ errmsg ("%s only supports scalar arguments" ,
6899
+ msghdr )));
6831
6900
}
6832
6901
6833
6902
agtv_value = get_ith_agtype_value_from_container (& agt_arg -> root , 0 );
6834
6903
6835
6904
if (agtv_value -> type == AGTV_NULL )
6836
6905
{
6837
- PG_RETURN_NULL () ;
6906
+ return NULL ;
6838
6907
}
6839
6908
else if (agtv_value -> type == AGTV_INTEGER )
6840
6909
{
@@ -6863,17 +6932,24 @@ Datum age_tostring(PG_FUNCTION_ARGS)
6863
6932
else
6864
6933
{
6865
6934
ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6866
- errmsg ("toString() unsupported argument agtype %d" ,
6867
- agtv_value -> type )));
6935
+ errmsg ("%s unsupported argument agtype %d" ,
6936
+ msghdr , agtv_value -> type )));
6868
6937
}
6869
6938
}
6939
+ /* it is an unknown type */
6940
+ else
6941
+ {
6942
+ ereport (ERROR , (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6943
+ errmsg ("%s unknown argument agtype %d" ,
6944
+ msghdr , type )));
6945
+ }
6870
6946
6871
6947
/* build the result */
6872
- agtv_result . type = AGTV_STRING ;
6873
- agtv_result . val .string .val = string ;
6874
- agtv_result . val .string .len = strlen (string );
6948
+ agtv_result -> type = AGTV_STRING ;
6949
+ agtv_result -> val .string .val = string ;
6950
+ agtv_result -> val .string .len = strlen (string );
6875
6951
6876
- PG_RETURN_POINTER ( agtype_value_to_agtype ( & agtv_result )) ;
6952
+ return agtv_result ;
6877
6953
}
6878
6954
6879
6955
PG_FUNCTION_INFO_V1 (age_tostringlist );
0 commit comments