From 51ca8252baad7c7336ac59b4fef8734b6fc8fd6e Mon Sep 17 00:00:00 2001 From: John Gemignani Date: Wed, 8 Nov 2023 08:55:33 -0800 Subject: [PATCH] Clean up agtype_to_int8, agtype_to_int4, & agtype_to_int2 (#1354) (#1372) Cleaned up the code in `agtype_to_int8`, `agtype_to_int4`, and `agtype_to_int2`. There was some dead code after implementing PR 1339. Additionally, modified the error messages to be a bit more helpful and modified the logic to cover a few more cases. Added more regression tests. --- regress/expected/agtype.out | 12 ++++++ regress/sql/agtype.sql | 7 +++- src/backend/utils/adt/agtype.c | 77 +++++++++++++++++++++++++--------- 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/regress/expected/agtype.out b/regress/expected/agtype.out index 103a61ba9..d23e3f1fb 100644 --- a/regress/expected/agtype.out +++ b/regress/expected/agtype.out @@ -2301,6 +2301,10 @@ SELECT agtype_to_int8(Inf); ERROR: column "inf" does not exist LINE 1: SELECT agtype_to_int8(Inf); ^ +SELECT agtype_to_int8('{"name":"John"}'); +ERROR: invalid agtype string to int8 type: 17 +SELECT agtype_to_int8('[1,2,3]'); +ERROR: invalid agtype string to int8 type: 16 -- -- Test boolean to integer cast -- @@ -2431,6 +2435,10 @@ SELECT agtype_to_int4(Inf); ERROR: column "inf" does not exist LINE 1: SELECT agtype_to_int4(Inf); ^ +SELECT agtype_to_int4('{"name":"John"}'); +ERROR: invalid agtype string to int4 type: 17 +SELECT agtype_to_int4('[1,2,3]'); +ERROR: invalid agtype string to int4 type: 16 -- -- Test boolean to integer2 cast -- @@ -2561,6 +2569,10 @@ SELECT agtype_to_int2(Inf); ERROR: column "inf" does not exist LINE 1: SELECT agtype_to_int2(Inf); ^ +SELECT agtype_to_int2('{"name":"John"}'); +ERROR: invalid agtype string to int2 type: 17 +SELECT agtype_to_int2('[1,2,3]'); +ERROR: invalid agtype string to int2 type: 16 -- -- Test agtype to int[] -- diff --git a/regress/sql/agtype.sql b/regress/sql/agtype.sql index 42bd2523b..10ffc5772 100644 --- a/regress/sql/agtype.sql +++ b/regress/sql/agtype.sql @@ -573,6 +573,8 @@ SELECT agtype_to_int8('NaN'); SELECT agtype_to_int8('Inf'); SELECT agtype_to_int8(NaN); SELECT agtype_to_int8(Inf); +SELECT agtype_to_int8('{"name":"John"}'); +SELECT agtype_to_int8('[1,2,3]'); -- -- Test boolean to integer cast @@ -608,7 +610,8 @@ SELECT agtype_to_int4('NaN'); SELECT agtype_to_int4('Inf'); SELECT agtype_to_int4(NaN); SELECT agtype_to_int4(Inf); - +SELECT agtype_to_int4('{"name":"John"}'); +SELECT agtype_to_int4('[1,2,3]'); -- -- Test boolean to integer2 cast -- @@ -643,6 +646,8 @@ SELECT agtype_to_int2('NaN'); SELECT agtype_to_int2('Inf'); SELECT agtype_to_int2(NaN); SELECT agtype_to_int2(Inf); +SELECT agtype_to_int2('{"name":"John"}'); +SELECT agtype_to_int2('[1,2,3]'); -- -- Test agtype to int[] diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c index 55c63f4f5..59c2e7f43 100644 --- a/src/backend/utils/adt/agtype.c +++ b/src/backend/utils/adt/agtype.c @@ -2629,14 +2629,21 @@ Datum agtype_to_int8(PG_FUNCTION_ARGS) { agtype_value *temp = NULL; - /* convert the string to an agtype_value */ + /* + * Convert the string to an agtype_value. Remember that a returned + * scalar value is returned in a one element array. + */ temp = agtype_value_from_cstring(agtv_p->val.string.val, agtv_p->val.string.len); + /* this will catch anything that isn't an array and isn't a scalar */ if (temp->type != AGTV_ARRAY || !temp->val.array.raw_scalar) { - elog(ERROR, "invalid agtype type: %d", (int)agtv_p->type); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid agtype string to int8 type: %d", + (int)temp->type))); } /* save the top agtype_value */ @@ -2644,6 +2651,7 @@ Datum agtype_to_int8(PG_FUNCTION_ARGS) /* get the wrapped agtype_value */ temp = &temp->val.array.elems[0]; + /* these we expect */ if (temp->type == AGTV_FLOAT || temp->type == AGTV_INTEGER || temp->type == AGTV_NUMERIC || @@ -2651,6 +2659,11 @@ Datum agtype_to_int8(PG_FUNCTION_ARGS) { agtv_p = temp; } + else + { + elog(ERROR, "unexpected string type: %d in agtype_to_int8", + (int)temp->type); + } } /* now check the rest */ @@ -2674,7 +2687,10 @@ Datum agtype_to_int8(PG_FUNCTION_ARGS) } else { - elog(ERROR, "invalid agtype type: %d", (int)agtv_p->type); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid conversion type in agtype_to_int8: %d", + (int)agtv_p->type))); } /* free the container, if it was used */ @@ -2733,14 +2749,21 @@ Datum agtype_to_int4(PG_FUNCTION_ARGS) { agtype_value *temp = NULL; - /* convert the string to an agtype_value */ + /* + * Convert the string to an agtype_value. Remember that a returned + * scalar value is returned in a one element array. + */ temp = agtype_value_from_cstring(agtv_p->val.string.val, agtv_p->val.string.len); + /* this will catch anything that isn't an array and isn't a scalar */ if (temp->type != AGTV_ARRAY || !temp->val.array.raw_scalar) { - elog(ERROR, "invalid agtype type: %d", (int)agtv_p->type); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid agtype string to int4 type: %d", + (int)temp->type))); } /* save the top agtype_value */ @@ -2748,6 +2771,7 @@ Datum agtype_to_int4(PG_FUNCTION_ARGS) /* get the wrapped agtype_value */ temp = &temp->val.array.elems[0]; + /* these we expect */ if (temp->type == AGTV_FLOAT || temp->type == AGTV_INTEGER || temp->type == AGTV_NUMERIC || @@ -2755,6 +2779,11 @@ Datum agtype_to_int4(PG_FUNCTION_ARGS) { agtv_p = temp; } + else + { + elog(ERROR, "unexpected string type: %d in agtype_to_int4", + (int)temp->type); + } } /* now check the rest */ @@ -2773,18 +2802,16 @@ Datum agtype_to_int4(PG_FUNCTION_ARGS) result = DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(agtv_p->val.numeric))); } - else if (agtv_p->type == AGTV_STRING) - { - result = DatumGetInt32(DirectFunctionCall1(int4in, - CStringGetDatum(agtv_p->val.string.val))); - } else if (agtv_p->type == AGTV_BOOL) { result = (agtv_p->val.boolean) ? 1 : 0; } else { - elog(ERROR, "invalid agtype type: %d", (int)agtv_p->type); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid conversion type in agtype_to_int4: %d", + (int)agtv_p->type))); } /* free the container, if it was used */ @@ -2843,14 +2870,21 @@ Datum agtype_to_int2(PG_FUNCTION_ARGS) { agtype_value *temp = NULL; - /* convert the string to an agtype_value */ + /* + * Convert the string to an agtype_value. Remember that a returned + * scalar value is returned in a one element array. + */ temp = agtype_value_from_cstring(agtv_p->val.string.val, agtv_p->val.string.len); + /* this will catch anything that isn't an array and isn't a scalar */ if (temp->type != AGTV_ARRAY || !temp->val.array.raw_scalar) { - elog(ERROR, "invalid agtype type: %d", (int)agtv_p->type); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid agtype string to int2 type: %d", + (int)temp->type))); } /* save the top agtype_value */ @@ -2858,6 +2892,7 @@ Datum agtype_to_int2(PG_FUNCTION_ARGS) /* get the wrapped agtype_value */ temp = &temp->val.array.elems[0]; + /* these we expect */ if (temp->type == AGTV_FLOAT || temp->type == AGTV_INTEGER || temp->type == AGTV_NUMERIC || @@ -2865,6 +2900,11 @@ Datum agtype_to_int2(PG_FUNCTION_ARGS) { agtv_p = temp; } + else + { + elog(ERROR, "unexpected string type: %d in agtype_to_int2", + (int)temp->type); + } } /* now check the rest */ @@ -2883,18 +2923,17 @@ Datum agtype_to_int2(PG_FUNCTION_ARGS) result = DatumGetInt16(DirectFunctionCall1(numeric_int2, NumericGetDatum(agtv_p->val.numeric))); } - else if (agtv_p->type == AGTV_STRING) - { - result = DatumGetInt16(DirectFunctionCall1(int2in, - CStringGetDatum(agtv_p->val.string.val))); - } else if (agtv_p->type == AGTV_BOOL) { result = (agtv_p->val.boolean) ? 1 : 0; } else { - elog(ERROR, "invalid agtype type: %d", (int)agtv_p->type); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid conversion type in agtype_to_int2: %d", + (int)agtv_p->type))); + } /* free the container, if it was used */