This is an automated email from the ASF dual-hosted git repository.
dehowef pushed a commit to branch PG12
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/PG12 by this push:
new a4a8b2cd Added the toStringList() function PG12 (#1086)
a4a8b2cd is described below
commit a4a8b2cd5fcd982b9ff3aa0e2d2c724d0620f64b
Author: Marcos Silva <[email protected]>
AuthorDate: Tue Aug 8 15:34:27 2023 -0300
Added the toStringList() function PG12 (#1086)
- This function is inspired by the "tostringlist" function in
OpenCypher.https://neo4j.com/docs/cypher-manual/current/functions/list/#functions-tostringlist
- toStringList() converts a list of values and returns a list of string
values. If any values are not convertible to string they will be null in the
list returned.
- A list containing the converted elements; depending on the input value a
converted value is either a string value or null.
- Also added the regression tests
---
age--1.3.0.sql | 8 ++++
regress/expected/expr.out | 63 +++++++++++++++++++++++++
regress/sql/expr.sql | 28 +++++++++++-
src/backend/utils/adt/agtype.c | 101 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 199 insertions(+), 1 deletion(-)
diff --git a/age--1.3.0.sql b/age--1.3.0.sql
index 3a257820..b90ba32b 100644
--- a/age--1.3.0.sql
+++ b/age--1.3.0.sql
@@ -3545,6 +3545,14 @@ RETURNS NULL ON NULL INPUT
PARALLEL SAFE
AS 'MODULE_PATHNAME';
+CREATE FUNCTION ag_catalog.age_tostringlist(variadic "any")
+RETURNS agtype
+LANGUAGE c
+IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
CREATE FUNCTION ag_catalog.age_size(variadic "any")
RETURNS agtype
LANGUAGE c
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index 612b5697..6c0266e9 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -3276,6 +3276,69 @@ ERROR: function ag_catalog.age_tostring() does not exist
LINE 1: SELECT * FROM cypher('expr', $$ RETURN toString() $$) AS (re...
^
HINT: No function matches the given name and argument types. You might need
to add explicit type casts.
+-- toStringList() --
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([5, 10, 7.8, 9, 1.3])
+$$) AS (toStringList agtype);
+ tostringlist
+--------------------------------
+ ["5", "10", "7.8", "9", "1.3"]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList(['test', 89, 'again', 7.1, 9])
+$$) AS (toStringList agtype);
+ tostringlist
+-------------------------------------
+ ["test", "89", "again", "7.1", "9"]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([null, false, true, 'string'])
+$$) AS (toStringList agtype);
+ tostringlist
+------------------------------
+ [null, null, null, "string"]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([9.123456789, 5.123, 1.12345, 0.123123])
+$$) AS (toStringList agtype);
+ tostringlist
+-------------------------------------------------
+ ["9.123456789", "5.123", "1.12345", "0.123123"]
+(1 row)
+
+-- should return null
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([null])
+$$) AS (toStringList agtype);
+ tostringlist
+--------------
+ [null]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([true, false, true, true])
+$$) AS (toStringList agtype);
+ tostringlist
+--------------------------
+ [null, null, null, null]
+(1 row)
+
+-- should fail
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([['a', b]])
+$$) AS (toStringList agtype);
+ERROR: could not find rte for b
+LINE 2: RETURN toStringList([['a', b]])
+ ^
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([test])
+$$) AS (toStringList agtype);
+ERROR: could not find rte for test
+LINE 2: RETURN toStringList([test])
+ ^
--
-- reverse(string)
--
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index a241b0b4..d2248497 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -1441,7 +1441,33 @@ SELECT * FROM age_toString(agtype_in(null));
-- should fail
SELECT * FROM age_toString();
SELECT * FROM cypher('expr', $$ RETURN toString() $$) AS (results agtype);
-
+-- toStringList() --
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([5, 10, 7.8, 9, 1.3])
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList(['test', 89, 'again', 7.1, 9])
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([null, false, true, 'string'])
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([9.123456789, 5.123, 1.12345, 0.123123])
+$$) AS (toStringList agtype);
+-- should return null
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([null])
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([true, false, true, true])
+$$) AS (toStringList agtype);
+-- should fail
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([['a', b]])
+$$) AS (toStringList agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN toStringList([test])
+$$) AS (toStringList agtype);
--
-- reverse(string)
--
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 7428c349..540f2e6b 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -31,6 +31,7 @@
#include "postgres.h"
#include <math.h>
+#include <float.h>
#include "access/genam.h"
#include "access/heapam.h"
@@ -6145,6 +6146,106 @@ Datum age_tostring(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(agtype_value_to_agtype(&agtv_result));
}
+PG_FUNCTION_INFO_V1(age_tostringlist);
+/*
+ * toStringList() converts a list of values and returns a list of String
values.
+ * If any values are not convertible to string point they will be null in the
list returned.
+ */
+Datum age_tostringlist(PG_FUNCTION_ARGS)
+{
+ agtype *agt_arg = NULL;
+ agtype_in_state agis_result;
+ agtype_value *elem;
+ agtype_value string_elem;
+ int count;
+ int i;
+ float float_num;
+ int float_size;
+ char buffer[64];
+
+ /* check for null */
+ if (PG_ARGISNULL(0))
+ {
+ PG_RETURN_NULL();
+ }
+ agt_arg = AG_GET_ARG_AGTYPE_P(0);
+ /* check for an array */
+ if (!AGT_ROOT_IS_ARRAY(agt_arg) || AGT_ROOT_IS_SCALAR(agt_arg))
+ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("toStringList() argument must resolve to a list
or null")));
+
+ count = AGT_ROOT_COUNT(agt_arg);
+
+ /* if we have an empty list or only one element in the list, return null */
+ if (count == 0)
+ PG_RETURN_NULL();
+
+ /* clear the result structure */
+ MemSet(&agis_result, 0, sizeof(agtype_in_state));
+
+ /* push the beginning of the array */
+ agis_result.res = push_agtype_value(&agis_result.parse_state,
+ WAGT_BEGIN_ARRAY, NULL);
+
+ /* iterate through the list */
+ for (i = 0; i < count; i++)
+ {
+ // TODO: check element's type, it's value, and convert it to string if
possible.
+ elem = get_ith_agtype_value_from_container(&agt_arg->root, i);
+ string_elem.type = AGTV_STRING;
+
+ switch (elem->type)
+ {
+ case AGTV_STRING:
+
+ if(!elem)
+ {
+ string_elem.type = AGTV_NULL;
+
+ agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_ELEM, &string_elem);
+ }
+
+ string_elem.val.string.val = elem->val.string.val;
+ string_elem.val.string.len = elem->val.string.len;
+
+ agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_ELEM, &string_elem);
+
+ break;
+
+ case AGTV_FLOAT:
+
+ float_num = elem->val.float_value;
+ sprintf(buffer, "%.*g", DBL_DIG, elem->val.float_value);
+ string_elem.val.string.val = pstrdup(buffer);
+ string_elem.val.string.len = strlen(buffer);
+
+ agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_ELEM, &string_elem);
+
+ break;
+
+ case AGTV_INTEGER:
+
+ sprintf(buffer, "%d", elem->val.int_value);
+ string_elem.val.string.val = pstrdup(buffer);
+ string_elem.val.string.len = strlen(buffer);
+
+ agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_ELEM, &string_elem);
+
+ break;
+
+ default:
+
+ string_elem.type = AGTV_NULL;
+ agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_ELEM, &string_elem);
+
+ break;
+ }
+ }
+ agis_result.res = push_agtype_value(&agis_result.parse_state,
WAGT_END_ARRAY, NULL);
+
+ PG_RETURN_POINTER(agtype_value_to_agtype(agis_result.res));
+}
+
static agtype_iterator *get_next_list_element(agtype_iterator *it,
agtype_container *agtc, agtype_value *elem)
{