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 058235ee add toIntegerList() function (#1058)
058235ee is described below

commit 058235ee7d947138e957da90c29e14ba0c8cd017
Author: Marcos Silva <[email protected]>
AuthorDate: Tue Jul 18 18:50:57 2023 -0300

    add toIntegerList() function (#1058)
    
    - This function is inspired by 
https://neo4j.com/docs/cypher-manual/current/functions/list/#functions-tointegerlist
 in OpenCypher.
    - The function toIntegerList() takes a list of values and produces a new 
list containing only the integer values. If any values cannot be converted to 
an integer, they will be represented as null in the returned list.
    - The result of the toIntegerList() function is a list that contains the 
converted elements. The converted values in the list can be either integer 
values or null, depending on the input value.
    - Also added the regression tests.
---
 age--1.3.0.sql                 |   8 +++
 regress/expected/expr.out      |  69 ++++++++++++++++++++++++
 regress/sql/expr.sql           |  30 +++++++++++
 src/backend/utils/adt/agtype.c | 118 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 225 insertions(+)

diff --git a/age--1.3.0.sql b/age--1.3.0.sql
index 1f6a8acf..3a257820 100644
--- a/age--1.3.0.sql
+++ b/age--1.3.0.sql
@@ -3529,6 +3529,14 @@ RETURNS NULL ON NULL INPUT
 PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
+CREATE FUNCTION ag_catalog.age_tointegerlist(variadic "any")
+RETURNS agtype
+LANGUAGE c
+IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
 CREATE FUNCTION ag_catalog.age_tostring(variadic "any")
 RETURNS agtype
 LANGUAGE c
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index cc1ed8e2..612b5697 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -3032,6 +3032,75 @@ ERROR:  function ag_catalog.age_tointeger() does not 
exist
 LINE 2:     RETURN toInteger()
                    ^
 HINT:  No function matches the given name and argument types. You might need 
to add explicit type casts.
+-- toIntegerList()
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([1, 7.8, 9.0, '88'])
+$$) AS (toIntegerList agtype);
+ tointegerlist 
+---------------
+ [1, 7, 9, 88]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([4.2, '123', '8', 8])
+$$) AS (toIntegerList agtype);
+ tointegerlist  
+----------------
+ [4, 123, 8, 8]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(['41', '12', 2])
+$$) AS (toIntegerList agtype);
+ tointegerlist 
+---------------
+ [41, 12, 2]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([1, 2, 3, '10.2'])
+$$) AS (toIntegerList agtype);
+ tointegerlist 
+---------------
+ [1, 2, 3, 10]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([0000])
+$$) AS (toIntegerList agtype);
+ tointegerlist 
+---------------
+ [0]
+(1 row)
+
+-- should return null
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(["false_", 'asdsad', '123k1kdk1'])
+$$) AS (toIntegerList agtype);
+   tointegerlist    
+--------------------
+ [null, null, null]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([null, '123false', 'one'])
+$$) AS (toIntegerList agtype);
+   tointegerlist    
+--------------------
+ [null, null, null]
+(1 row)
+
+-- should fail
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(123, '123')
+$$) AS (toIntegerList agtype);
+ERROR:  toIntegerList() argument must resolve to a list or null
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(32[])
+$$) AS (toIntegerList agtype);
+ERROR:  syntax error at or near "]"
+LINE 2:     RETURN toIntegerList(32[])
+                                    ^
 -- length() of a path
 SELECT * FROM cypher('expr', $$
     RETURN length([{id: 0, label: "vertex 0", properties: {}}::vertex, {id: 2, 
label: "edge 0", end_id: 1, start_id: 0, properties: {}}::edge, {id: 1, label: 
"vertex 1", properties: {}}::vertex]::path)
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index 744a071f..a241b0b4 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -1362,6 +1362,36 @@ $$) AS (toInteger agtype);
 SELECT * FROM cypher('expr', $$
     RETURN toInteger()
 $$) AS (toInteger agtype);
+-- toIntegerList()
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([1, 7.8, 9.0, '88'])
+$$) AS (toIntegerList agtype);
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([4.2, '123', '8', 8])
+$$) AS (toIntegerList agtype);
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(['41', '12', 2])
+$$) AS (toIntegerList agtype);
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([1, 2, 3, '10.2'])
+$$) AS (toIntegerList agtype);
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([0000])
+$$) AS (toIntegerList agtype);
+-- should return null
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(["false_", 'asdsad', '123k1kdk1'])
+$$) AS (toIntegerList agtype);
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList([null, '123false', 'one'])
+$$) AS (toIntegerList agtype);
+-- should fail
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(123, '123')
+$$) AS (toIntegerList agtype);
+SELECT * FROM cypher('expr', $$
+    RETURN toIntegerList(32[])
+$$) AS (toIntegerList agtype);
 -- length() of a path
 SELECT * FROM cypher('expr', $$
     RETURN length([{id: 0, label: "vertex 0", properties: {}}::vertex, {id: 2, 
label: "edge 0", end_id: 1, start_id: 0, properties: {}}::edge, {id: 1, label: 
"vertex 1", properties: {}}::vertex]::path)
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 6ffce718..7428c349 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -5599,6 +5599,124 @@ Datum age_tointeger(PG_FUNCTION_ARGS)
     PG_RETURN_POINTER(agtype_value_to_agtype(&agtv_result));
 }
 
+PG_FUNCTION_INFO_V1(age_tointegerlist);
+/*
+ * toIntegerList() converts a list of values and returns a list of integers 
point values. 
+ * If any values are not convertible to integer they will be null in the list 
returned.
+ */
+Datum age_tointegerlist(PG_FUNCTION_ARGS)
+{
+    agtype *agt_arg = NULL;
+    agtype_in_state agis_result;
+    agtype_value *elem;
+    agtype_value integer_elem;
+    int count;
+    int i;
+    char *string = NULL;
+    int integer_num;
+    float float_num;
+    int is_float;
+
+    /* 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("toIntegerList() 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 integer 
if possible.
+        elem = get_ith_agtype_value_from_container(&agt_arg->root, i);
+        integer_elem.type = AGTV_INTEGER;
+
+        switch (elem->type)
+        {
+        case AGTV_STRING:
+
+            string = elem->val.string.val;
+            integer_elem.type = AGTV_INTEGER;
+            integer_elem.val.int_value = atoi(string);
+
+            if (*string == '+' || *string == '-' || (*string >= '0' && *string 
<= '9'))
+            {
+                is_float = 1;
+                while (*(++string))
+                {
+
+                    if(!(*string >= '0' && *string <= '9'))
+                    {
+                        if(*string == '.' && is_float)
+                        {
+                            is_float--;
+                        }
+                        else
+                        {
+                            integer_elem.type = AGTV_NULL;
+                            break;
+                        }
+                    }
+                }   
+            }
+            else
+            {
+
+                integer_elem.type = AGTV_NULL;
+            }
+
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &integer_elem);
+
+            break;
+
+        case AGTV_FLOAT:
+
+            integer_elem.type = AGTV_INTEGER;
+            float_num = elem->val.float_value;
+            integer_elem.val.int_value = (int)float_num;
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &integer_elem);
+
+            break;
+
+        case AGTV_INTEGER:
+
+            integer_elem.type = AGTV_INTEGER;
+            integer_num = elem->val.int_value;
+            integer_elem.val.int_value = integer_num;
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &integer_elem);
+
+            break;
+
+        default:
+
+            integer_elem.type = AGTV_NULL;
+            agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM, &integer_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));
+}
+
 PG_FUNCTION_INFO_V1(age_size);
 
 Datum age_size(PG_FUNCTION_ARGS)

Reply via email to