From 2da7a9d0cf2ba5d3162720d4bc35cbf08477fc40 Mon Sep 17 00:00:00 2001 From: John Gemignani Date: Thu, 13 Jul 2023 11:59:13 -0700 Subject: [PATCH] Add REGTYPEOID to toString function Added the REGTYPEOID to the toString function. This will help in debugging by allowing pg_typeof to work with AGE. For example - psql-13.9-5432-pgsql=# SELECT * FROM cypher('graph',$$ MATCH ()<-[x *]-() RETURN toString(pg_catalog.pg_typeof(x)) $$) as (a agtype); a ---------- "agtype" "agtype" "agtype" (3 rows) Added regression tests. --- regress/expected/expr.out | 29 ++++++++++++++++---- regress/sql/expr.sql | 14 ++++++---- src/backend/utils/adt/agtype.c | 49 ++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/regress/expected/expr.out b/regress/expected/expr.out index 37c7849b0..5ed3cd43c 100644 --- a/regress/expected/expr.out +++ b/regress/expected/expr.out @@ -900,7 +900,7 @@ $$) AS r(result boolean); (1 row) SELECT * FROM cypher('expr', $$ -RETURN false OR 1::bool +RETURN false OR 1::bool $$) AS (result boolean); result -------- @@ -916,7 +916,7 @@ $$) AS (result boolean); (1 row) SELECT * FROM cypher('expr', $$ -RETURN NOT 1::bool::int::bool +RETURN NOT 1::bool::int::bool $$) AS (result boolean); result -------- @@ -937,11 +937,11 @@ RETURN false OR 1 $$) AS r(result boolean); ERROR: cannot cast agtype integer to type boolean SELECT * FROM cypher('expr', $$ -RETURN 0 OR true +RETURN 0 OR true $$) AS r(result boolean); ERROR: cannot cast agtype integer to type boolean SELECT * FROM cypher('expr', $$ -RETURN NOT 1 +RETURN NOT 1 $$) AS r(result boolean); ERROR: cannot cast agtype integer to type boolean SELECT * FROM cypher('expr', $$ @@ -969,7 +969,7 @@ RETURN false XOR 1::numeric $$) AS (result agtype); ERROR: cannot cast agtype numeric to type boolean SELECT * FROM cypher('expr', $$ -RETURN false OR 1::bool::int +RETURN false OR 1::bool::int $$) AS (result boolean); ERROR: cannot cast agtype integer to type boolean -- @@ -3055,6 +3055,12 @@ SELECT * FROM age_toString('a text string'::text); "a text string" (1 row) +SELECT * FROM age_toString(pg_typeof(3.14)); + age_tostring +-------------- + "numeric" +(1 row) + -- agtypes SELECT * FROM age_toString(agtype_in('3')); age_tostring @@ -6684,6 +6690,19 @@ SELECT * FROM cypher('list',$$ MATCH p=(n:xyz)-[e]->() SET n.array=[0, 1, 2, 3, {"id": 1970324836974597, "label": "xyz", "properties": {"array": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100], 100]}}::vertex | {"id": 2251799813685249, "label": "KNOWS", "end_id": 1970324836974598, "start_id": 1970324836974597, "properties": {"array": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]}}::edge (1 row) +-- pg_typeof +SELECT * FROM cypher('expr', $$MATCH (u) RETURN toString(pg_catalog.pg_typeof(u.id)) $$) AS (u agtype); + u +---------- + "agtype" + "agtype" + "agtype" + "agtype" + "agtype" + "agtype" + "agtype" +(7 rows) + -- -- Cleanup -- diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql index c9547e332..d1a369952 100644 --- a/regress/sql/expr.sql +++ b/regress/sql/expr.sql @@ -395,7 +395,7 @@ RETURN false XOR false $$) AS r(result boolean); SELECT * FROM cypher('expr', $$ -RETURN false OR 1::bool +RETURN false OR 1::bool $$) AS (result boolean); SELECT * FROM cypher('expr', $$ @@ -403,7 +403,7 @@ RETURN false AND NOT 1::bool $$) AS (result boolean); SELECT * FROM cypher('expr', $$ -RETURN NOT 1::bool::int::bool +RETURN NOT 1::bool::int::bool $$) AS (result boolean); -- Invalid operands for AND, OR, NOT, XOR @@ -420,11 +420,11 @@ RETURN false OR 1 $$) AS r(result boolean); SELECT * FROM cypher('expr', $$ -RETURN 0 OR true +RETURN 0 OR true $$) AS r(result boolean); SELECT * FROM cypher('expr', $$ -RETURN NOT 1 +RETURN NOT 1 $$) AS r(result boolean); SELECT * FROM cypher('expr', $$ @@ -452,7 +452,7 @@ RETURN false XOR 1::numeric $$) AS (result agtype); SELECT * FROM cypher('expr', $$ -RETURN false OR 1::bool::int +RETURN false OR 1::bool::int $$) AS (result boolean); -- -- Test indirection transform logic for object.property, object["property"], @@ -1362,6 +1362,7 @@ SELECT * FROM age_toString(false); SELECT * FROM age_toString('a string'); SELECT * FROM age_toString('a cstring'::cstring); SELECT * FROM age_toString('a text string'::text); +SELECT * FROM age_toString(pg_typeof(3.14)); -- agtypes SELECT * FROM age_toString(agtype_in('3')); SELECT * FROM age_toString(agtype_in('3.14')); @@ -2709,6 +2710,9 @@ SELECT * FROM cypher('list',$$ MATCH p=(n:xyz)-[e]->() SET n.array=[0, 1, 2, 3, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, e.array, 100] return n,e $$) as (a agtype, b agtype); +-- pg_typeof +SELECT * FROM cypher('expr', $$MATCH (u) RETURN toString(pg_catalog.pg_typeof(u.id)) $$) AS (u agtype); + -- -- Cleanup -- diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c index 3f26d183a..1fb5dc0d1 100644 --- a/src/backend/utils/adt/agtype.c +++ b/src/backend/utils/adt/agtype.c @@ -5785,15 +5785,20 @@ Datum age_tostring(PG_FUNCTION_ARGS) /* check number of args */ if (nargs > 1) + { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("toString() only supports one argument"))); + } + /* check for null */ if (nargs < 0 || nulls[0]) + { PG_RETURN_NULL(); + } /* - * toString() supports integer, float, numeric, text, cstring, boolean or - * the agtype integer, float, numeric, string, boolean input + * toString() supports integer, float, numeric, text, cstring, boolean, + * regtype or the agtypes: integer, float, numeric, string, boolean input */ arg = args[0]; type = types[0]; @@ -5801,29 +5806,53 @@ Datum age_tostring(PG_FUNCTION_ARGS) if (type != AGTYPEOID) { if (type == INT2OID) + { string = DatumGetCString(DirectFunctionCall1(int8out, Int64GetDatum((int64) DatumGetInt16(arg)))); + } else if (type == INT4OID) + { string = DatumGetCString(DirectFunctionCall1(int8out, Int64GetDatum((int64) DatumGetInt32(arg)))); + } else if (type == INT8OID) + { string = DatumGetCString(DirectFunctionCall1(int8out, arg)); + } else if (type == FLOAT4OID) + { string = DatumGetCString(DirectFunctionCall1(float8out, arg)); + } else if (type == FLOAT8OID) + { string = DatumGetCString(DirectFunctionCall1(float8out, arg)); + } else if (type == NUMERICOID) + { string = DatumGetCString(DirectFunctionCall1(numeric_out, arg)); + } else if (type == CSTRINGOID) + { string = DatumGetCString(arg); + } else if (type == TEXTOID) + { string = text_to_cstring(DatumGetTextPP(arg)); + } else if (type == BOOLOID) + { string = DatumGetBool(arg) ? "true" : "false"; + } + else if (type == REGTYPEOID) + { + string = DatumGetCString(DirectFunctionCall1(regtypeout, arg)); + } else + { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("toString() unsupported argument type %d", type))); + } } else { @@ -5834,31 +5863,47 @@ Datum age_tostring(PG_FUNCTION_ARGS) agt_arg = DATUM_GET_AGTYPE_P(arg); if (!AGT_ROOT_IS_SCALAR(agt_arg)) + { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("toString() only supports scalar arguments"))); + } agtv_value = get_ith_agtype_value_from_container(&agt_arg->root, 0); if (agtv_value->type == AGTV_NULL) + { PG_RETURN_NULL(); + } else if (agtv_value->type == AGTV_INTEGER) + { string = DatumGetCString(DirectFunctionCall1(int8out, Int64GetDatum(agtv_value->val.int_value))); + } else if (agtv_value->type == AGTV_FLOAT) + { string = DatumGetCString(DirectFunctionCall1(float8out, Float8GetDatum(agtv_value->val.float_value))); + } else if (agtv_value->type == AGTV_STRING) + { string = pnstrdup(agtv_value->val.string.val, agtv_value->val.string.len); + } else if (agtv_value->type == AGTV_NUMERIC) + { string = DatumGetCString(DirectFunctionCall1(numeric_out, PointerGetDatum(agtv_value->val.numeric))); + } else if (agtv_value->type == AGTV_BOOL) + { string = (agtv_value->val.boolean) ? "true" : "false"; + } else + { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("toString() unsupported argument agtype %d", agtv_value->type))); + } } /* build the result */