Skip to content
Permalink
Browse files
Add to age_reverse function so that it can reverse an agtype list (#146)
  • Loading branch information
quocvietvuong committed Nov 30, 2021
1 parent 50fce50 commit 6b89697351aab8806136503d9806026b3cb927db
Showing 3 changed files with 205 additions and 4 deletions.
@@ -2597,6 +2597,91 @@ SELECT * FROM age_reverse(null);

(1 row)

-- should return error
SELECT * FROM age_reverse([4923, 'abc', 521, NULL, 487]);
ERROR: syntax error at or near "["
LINE 1: SELECT * FROM age_reverse([4923, 'abc', 521, NULL, 487]);
^
-- Should return the reversed list
SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 'abc', 521, NULL, 487])
$$) AS (u agtype);
u
-------------------------------
[487, null, 521, "abc", 4923]
(1 row)

SELECT * FROM cypher('expr', $$
RETURN reverse([4923])
$$) AS (u agtype);
u
--------
[4923]
(1 row)

SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257])
$$) as (u agtype);
u
-------------
[257, 4923]
(1 row)

SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, null])
$$) as (u agtype);
u
-------------------
[null, 257, 4923]
(1 row)

SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, 'tea'])
$$) as (u agtype);
u
--------------------
["tea", 257, 4923]
(1 row)

SELECT * FROM cypher('expr', $$
RETURN reverse([[1, 4, 7], 4923, [1, 2, 3], 'abc', 521, NULL, 487, ['fgt', 7, 10]])
$$) as (u agtype);
u
---------------------------------------------------------------------
[["fgt", 7, 10], 487, null, 521, "abc", [1, 2, 3], 4923, [1, 4, 7]]
(1 row)

SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, {test1: "key"}])
$$) as (u agtype);
u
-------------------------------
[{"test1": "key"}, 257, 4923]
(1 row)

SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, {test2: [1, 2, 3]}])
$$) as (u agtype);
u
-----------------------------------
[{"test2": [1, 2, 3]}, 257, 4923]
(1 row)

SELECT * FROM cypher('expr', $$
CREATE ({test: [1, 2, 3]})
$$) as (u agtype);
u
---
(0 rows)

SELECT * FROM cypher('expr', $$
MATCH (v) WHERE exists(v.test) RETURN reverse(v.test)
$$) as (u agtype);
u
-----------
[3, 2, 1]
(1 row)

-- should fail
SELECT * FROM cypher('expr', $$
RETURN reverse(true)
@@ -1160,6 +1160,40 @@ SELECT * FROM cypher('expr', $$
RETURN reverse(null)
$$) AS (results agtype);
SELECT * FROM age_reverse(null);
-- should return error
SELECT * FROM age_reverse([4923, 'abc', 521, NULL, 487]);
-- Should return the reversed list
SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 'abc', 521, NULL, 487])
$$) AS (u agtype);
SELECT * FROM cypher('expr', $$
RETURN reverse([4923])
$$) AS (u agtype);
SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257])
$$) as (u agtype);
SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, null])
$$) as (u agtype);
SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, 'tea'])
$$) as (u agtype);
SELECT * FROM cypher('expr', $$
RETURN reverse([[1, 4, 7], 4923, [1, 2, 3], 'abc', 521, NULL, 487, ['fgt', 7, 10]])
$$) as (u agtype);
SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, {test1: "key"}])
$$) as (u agtype);
SELECT * FROM cypher('expr', $$
RETURN reverse([4923, 257, {test2: [1, 2, 3]}])
$$) as (u agtype);
SELECT * FROM cypher('expr', $$
CREATE ({test: [1, 2, 3]})
$$) as (u agtype);
SELECT * FROM cypher('expr', $$
MATCH (v) WHERE exists(v.test) RETURN reverse(v.test)
$$) as (u agtype);

-- should fail
SELECT * FROM cypher('expr', $$
RETURN reverse(true)
@@ -159,6 +159,9 @@ static int64 get_int64_from_int_datums(Datum d, Oid type, char *funcname,
static agtype_iterator *get_next_object_key(agtype_iterator *it,
agtype_container *agtc,
agtype_value *key);
static agtype_iterator *get_next_list_element(agtype_iterator *it,
agtype_container *agtc,
agtype_value *elem);

PG_FUNCTION_INFO_V1(agtype_in);

@@ -4860,6 +4863,50 @@ Datum age_tostring(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(agtype_value_to_agtype(&agtv_result));
}

static agtype_iterator *get_next_list_element(agtype_iterator *it,
agtype_container *agtc, agtype_value *elem)
{
agtype_iterator_token itok;
agtype_value tmp;

/* verify input params */
Assert(agtc != NULL);
Assert(elem != NULL);

/* check to see if the container is empty */
if (AGTYPE_CONTAINER_SIZE(agtc) == 0)
{
return NULL;
}

/* if the passed iterator is NULL, this is the first time, create it */
if (it == NULL)
{
/* initial the iterator */
it = agtype_iterator_init(agtc);
/* get the first token */
itok = agtype_iterator_next(&it, &tmp, true);
/* it should be WAGT_BEGIN_ARRAY */
Assert(itok == WAGT_BEGIN_ARRAY);
}

/* the next token should be an element or the end of the array */
itok = agtype_iterator_next(&it, &tmp, true);
Assert(itok == WAGT_ELEM || WAGT_END_ARRAY);

/* if this is the end of the array return NULL */
if (itok == WAGT_END_ARRAY) {
return NULL;
}

/* this should be the element, copy it */
if (itok == WAGT_ELEM) {
memcpy(elem, &tmp, sizeof(agtype_value));
}

return it;
}

PG_FUNCTION_INFO_V1(age_reverse);

Datum age_reverse(PG_FUNCTION_ARGS)
@@ -4904,15 +4951,50 @@ Datum age_reverse(PG_FUNCTION_ARGS)
}
else
{
agtype *agt_arg;
agtype_value *agtv_value;
agtype *agt_arg = NULL;
agtype_value *agtv_value = NULL;
agtype_parse_state *parse_state = NULL;
agtype_value elem = {0};
agtype_iterator *it = NULL;
agtype_value tmp;
agtype_value *elems = NULL;
int num_elems;
int i;

/* get the agtype argument */
agt_arg = DATUM_GET_AGTYPE_P(arg);

if (!AGT_ROOT_IS_SCALAR(agt_arg))
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("reverse() only supports scalar arguments")));
{
agtv_value = push_agtype_value(&parse_state, WAGT_BEGIN_ARRAY, NULL);

while ((it = get_next_list_element(it, &agt_arg->root, &elem)))
{
agtv_value = push_agtype_value(&parse_state, WAGT_ELEM, &elem);
}

/* now reverse the list */
elems = parse_state->cont_val.val.array.elems;
num_elems = parse_state->cont_val.val.array.num_elems;

for(i = 0; i < num_elems/2; i++)
{
tmp = elems[i];
elems[i] = elems[num_elems - 1 - i];
elems[num_elems - 1 - i] = tmp;
}
/* reverse done*/

elems = NULL;

agtv_value = push_agtype_value(&parse_state, WAGT_END_ARRAY, NULL);

Assert(agtv_value != NULL);
Assert(agtv_value->type = AGTV_ARRAY);

PG_RETURN_POINTER(agtype_value_to_agtype(agtv_value));

}

agtv_value = get_ith_agtype_value_from_container(&agt_arg->root, 0);

0 comments on commit 6b89697

Please sign in to comment.