This is an automated email from the ASF dual-hosted git repository.

jgemignani pushed a commit to branch PG15
in repository https://gitbox.apache.org/repos/asf/age.git

commit 81233ced4b118fbf1ac42e8d2ab2c9e59c0e1144
Author: Matheus Farias de Oliveira Matsumoto 
<[email protected]>
AuthorDate: Tue Oct 17 16:07:56 2023 -0300

    Implemented age_tail function (#1283)
    
    age_tail() function returns a list containing all the elements,
    excluding the first one, from a list.
---
 age--1.4.0.sql                 |  8 +++++
 regress/expected/expr.out      | 39 +++++++++++++++++++++
 regress/sql/expr.sql           | 11 ++++++
 src/backend/utils/adt/agtype.c | 77 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 135 insertions(+)

diff --git a/age--1.4.0.sql b/age--1.4.0.sql
index 47e8163c..caebb22c 100644
--- a/age--1.4.0.sql
+++ b/age--1.4.0.sql
@@ -3590,6 +3590,14 @@ RETURNS NULL ON NULL INPUT
 PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
+CREATE FUNCTION ag_catalog.age_tail(variadic "any")
+RETURNS agtype
+LANGUAGE c
+IMMUTABLE
+RETURNS NULL ON NULL INPUT
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
 CREATE FUNCTION ag_catalog.age_properties(agtype)
 RETURNS agtype
 LANGUAGE c
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index d85b51de..8c1a26cd 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -6928,6 +6928,45 @@ SELECT * from cypher('list', $$RETURN range(0, null, 
-3)$$) as (range agtype);
 ERROR:  range(): neither start or end can be NULL
 SELECT * from cypher('list', $$RETURN range(0, -10.0, -3.0)$$) as (range 
agtype);
 ERROR:  range() unsupported argument type
+-- tail()
+-- should return the last elements of the list
+SELECT * FROM cypher('list', $$ RETURN tail([1,2,3,4,5]) $$) AS (tail agtype);
+     tail     
+--------------
+ [2, 3, 4, 5]
+(1 row)
+
+SELECT * FROM cypher('list', $$ RETURN tail(["a","b","c","d","e"]) $$) AS 
(tail agtype);
+         tail         
+----------------------
+ ["b", "c", "d", "e"]
+(1 row)
+
+-- should return null
+SELECT * FROM cypher('list', $$ RETURN tail([1]) $$) AS (tail agtype);
+ tail 
+------
+ 
+(1 row)
+
+SELECT * FROM cypher('list', $$ RETURN tail([]) $$) AS (tail agtype);
+ tail 
+------
+ 
+(1 row)
+
+-- should throw errors
+SELECT * FROM cypher('list', $$ RETURN tail(123) $$) AS (tail agtype);
+ERROR:  tail() argument must resolve to a list or null
+SELECT * FROM cypher('list', $$ RETURN tail(abc) $$) AS (tail agtype);
+ERROR:  could not find rte for abc
+LINE 1: SELECT * FROM cypher('list', $$ RETURN tail(abc) $$) AS (tai...
+                                                    ^
+SELECT * FROM cypher('list', $$ RETURN tail() $$) AS (tail agtype);
+ERROR:  function ag_catalog.age_tail() does not exist
+LINE 1: SELECT * FROM cypher('list', $$ RETURN tail() $$) AS (tail a...
+                                               ^
+HINT:  No function matches the given name and argument types. You might need 
to add explicit type casts.
 -- labels()
 SELECT * from cypher('list', $$CREATE (u:People {name: "John"}) RETURN u$$) as 
(Vertices agtype);
                                       vertices                                 
      
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index 26acc1b3..13d1ca3c 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -2830,6 +2830,17 @@ SELECT * from cypher('list', $$RETURN range(-10, 10, 
-1)$$) as (range agtype);
 SELECT * from cypher('list', $$RETURN range(null, -10, -3)$$) as (range 
agtype);
 SELECT * from cypher('list', $$RETURN range(0, null, -3)$$) as (range agtype);
 SELECT * from cypher('list', $$RETURN range(0, -10.0, -3.0)$$) as (range 
agtype);
+-- tail()
+-- should return the last elements of the list
+SELECT * FROM cypher('list', $$ RETURN tail([1,2,3,4,5]) $$) AS (tail agtype);
+SELECT * FROM cypher('list', $$ RETURN tail(["a","b","c","d","e"]) $$) AS 
(tail agtype);
+-- should return null
+SELECT * FROM cypher('list', $$ RETURN tail([1]) $$) AS (tail agtype);
+SELECT * FROM cypher('list', $$ RETURN tail([]) $$) AS (tail agtype);
+-- should throw errors
+SELECT * FROM cypher('list', $$ RETURN tail(123) $$) AS (tail agtype);
+SELECT * FROM cypher('list', $$ RETURN tail(abc) $$) AS (tail agtype);
+SELECT * FROM cypher('list', $$ RETURN tail() $$) AS (tail agtype);
 -- labels()
 SELECT * from cypher('list', $$CREATE (u:People {name: "John"}) RETURN u$$) as 
(Vertices agtype);
 SELECT * from cypher('list', $$CREATE (u:People {name: "Larry"}) RETURN u$$) 
as (Vertices agtype);
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 84eed592..e492a38b 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -5126,6 +5126,83 @@ Datum age_last(PG_FUNCTION_ARGS)
     PG_RETURN_POINTER(agtype_value_to_agtype(agtv_result));
 }
 
+
+PG_FUNCTION_INFO_V1(age_tail);
+/*
+ * Returns a list  containing all the elements, excluding the first one, from 
a list.
+ */
+Datum age_tail(PG_FUNCTION_ARGS)
+{
+    Oid arg_type;
+    agtype *agt_arg = NULL;
+    agtype *agt_result = NULL;
+    agtype_in_state agis_result;
+    int count;
+    int i;
+
+    /* check number of arguments */
+    if (PG_NARGS() < 1 || PG_NARGS() > 1)
+    {
+        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("age_tail() requires only one argument")));
+    }
+
+    /* get the data type */
+    arg_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
+
+    /* check the data type */
+    if (arg_type != AGTYPEOID)
+    {
+        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("age_tail() argument must be of type agtype")));
+    }
+
+    /* 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("tail() 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 <= 1)
+    {
+        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 beginning with the second item */
+    for (i = 1; i < count; i++)
+    {
+        agis_result.res = push_agtype_value(&agis_result.parse_state, 
WAGT_ELEM,
+                                            
get_ith_agtype_value_from_container(&agt_arg->root, i));
+    }
+
+    /* push the end of the array */
+    agis_result.res = push_agtype_value(&agis_result.parse_state,
+                                        WAGT_END_ARRAY, NULL);
+
+    agt_result = agtype_value_to_agtype(agis_result.res);
+    pfree_agtype_value(agis_result.res);
+
+    PG_RETURN_POINTER(agt_result);
+}
+
 PG_FUNCTION_INFO_V1(age_properties);
 
 Datum age_properties(PG_FUNCTION_ARGS)

Reply via email to