Skip to content

Commit

Permalink
Implemented age_tail function (#1283)
Browse files Browse the repository at this point in the history
age_tail() function returns a list containing all the elements,
excluding the first one, from a list.
  • Loading branch information
MatheusFarias03 committed Oct 17, 2023
1 parent 30532ec commit d48c008
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 0 deletions.
8 changes: 8 additions & 0 deletions age--1.4.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
39 changes: 39 additions & 0 deletions regress/expected/expr.out
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions regress/sql/expr.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
77 changes: 77 additions & 0 deletions src/backend/utils/adt/agtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit d48c008

Please sign in to comment.