This is an automated email from the ASF dual-hosted git repository.
rafsun42 pushed a commit to branch PG14
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/PG14 by this push:
new ccd9a406 Add checks for array functions to recognize and decode VPC
(#1064) (#1489)
ccd9a406 is described below
commit ccd9a4069fe98ec19166ed2d6b2bb6c4eb02396f
Author: John Gemignani <[email protected]>
AuthorDate: Thu Jan 4 16:13:24 2024 -0800
Add checks for array functions to recognize and decode VPC (#1064) (#1489)
* Add checks for array functions to recognize and decode VPC
- Added for array functions size, head, last, isEmpty, reverse,
agtype_in_operator and agtype_access_slice.
- Fixed a bug where object input to reverse would terminate the server
instead of erroring out.
- Added regression tests.
* Fix issue with in operator tranformation
- We need to build a function call here if the rexpr is already
tranformed. It can be already tranformed cypher_list as columnref.
Resolved -
Conflicts:
src/backend/parser/cypher_expr.c
Co-authored-by: Muhammad Taha Naveed <[email protected]>
---
regress/expected/expr.out | 349 +++++++++++++++++++++++++++++++++-
regress/sql/expr.sql | 158 ++++++++++++++++
src/backend/parser/cypher_expr.c | 32 ++--
src/backend/utils/adt/agtype.c | 391 ++++++++++++++++++++++++++++++---------
src/include/utils/agtype.h | 2 +
5 files changed, 830 insertions(+), 102 deletions(-)
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index 2c29b9c7..d8101506 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -323,13 +323,9 @@ $$RETURN 1 IN [[null]]$$) AS r(c boolean);
SELECT * FROM cypher('expr',
$$RETURN null IN 'str' $$) AS r(c boolean);
ERROR: object of IN must be a list
-LINE 2: $$RETURN null IN 'str' $$) AS r(c boolean);
- ^
SELECT * FROM cypher('expr',
$$RETURN 'str' IN 'str' $$) AS r(c boolean);
ERROR: object of IN must be a list
-LINE 2: $$RETURN 'str' IN 'str' $$) AS r(c boolean);
- ^
-- list access
SELECT * FROM cypher('expr',
$$RETURN [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10][0]$$) AS r(c agtype);
@@ -2801,6 +2797,16 @@ ERROR: function ag_catalog.age_size() does not exist
LINE 2: RETURN size()
^
HINT: No function matches the given name and argument types. You might need
to add explicit type casts.
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array[0]) = 0
+ RETURN vle_array
+$$) AS (vle_array agtype);
+ERROR: size() unsupported argument
+SELECT * FROM cypher('expr', $$
+ RETURN size({id: 0, status:'it_will_fail'})
+$$) AS (size agtype);
+ERROR: size() unsupported argument
-- head() of an array
SELECT * FROM cypher('expr', $$
RETURN head([1, 2, 3, 4, 5])
@@ -2835,6 +2841,14 @@ $$) AS (head agtype);
(1 row)
+SELECT * FROM cypher('expr', $$
+ RETURN head([null, null])
+$$) AS (head agtype);
+ head
+------
+
+(1 row)
+
-- should fail
SELECT * FROM cypher('expr', $$
RETURN head(1234567890)
@@ -2847,6 +2861,15 @@ ERROR: function ag_catalog.age_head() does not exist
LINE 2: RETURN head()
^
HINT: No function matches the given name and argument types. You might need
to add explicit type casts.
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN head(vle_array[0])
+$$) AS (head agtype);
+ERROR: head() argument must resolve to a list or null
+SELECT * FROM cypher('expr', $$
+ RETURN head({id: 0, status:'it_will_fail'})
+$$) AS (head agtype);
+ERROR: head() argument must resolve to a list or null
-- last()
SELECT * FROM cypher('expr', $$
RETURN last([1, 2, 3, 4, 5])
@@ -2881,6 +2904,14 @@ $$) AS (last agtype);
(1 row)
+SELECT * FROM cypher('expr', $$
+ RETURN last([null, null])
+$$) AS (last agtype);
+ last
+------
+
+(1 row)
+
-- should fail
SELECT * FROM cypher('expr', $$
RETURN last(1234567890)
@@ -2893,6 +2924,15 @@ ERROR: function ag_catalog.age_last() does not exist
LINE 2: RETURN last()
^
HINT: No function matches the given name and argument types. You might need
to add explicit type casts.
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN last(vle_array[0])
+$$) AS (last agtype);
+ERROR: last() argument must resolve to a list or null
+SELECT * FROM cypher('expr', $$
+ RETURN last({id: 0, status:'it_will_fail'})
+$$) AS (last agtype);
+ERROR: last() argument must resolve to a list or null
-- properties()
SELECT * FROM cypher('expr', $$
MATCH (v) RETURN properties(v)
@@ -3821,6 +3861,15 @@ ERROR: function age_reverse() does not exist
LINE 1: SELECT * FROM age_reverse();
^
HINT: No function matches the given name and argument types. You might need
to add explicit type casts.
+SELECT * FROM cypher('expr', $$
+ MATCH (v)
+ RETURN reverse(v)
+$$) AS (results agtype);
+ERROR: reverse() unsupported argument agtype 6
+SELECT * FROM cypher('expr', $$
+ RETURN reverse({})
+$$) AS (results agtype);
+ERROR: reverse() unsupported argument agtype
--
-- toUpper() and toLower()
--
@@ -7736,6 +7785,298 @@ SELECT * FROM cypher('graph_395', $$ MATCH
(p:Project)-[:Has]->(t:Task)-[:Assign
{"pn": "Project B", "tasks": [{"tn": "Task C", "users": [{"id":
1407374883553282, "label": "Person", "properties": {"age": 43, "name":
"Bob"}}::vertex]}]}
(2 rows)
+--
+-- issue 1044 - array functions not recognizing vpc
+--
+-- size
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) > 0
+ RETURN vle_array
+$$) AS (vle_array agtype);
+
vle_array
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) > 1
+ RETURN vle_array
+$$) AS (vle_array agtype);
+
vle_array
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(2 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) > 2
+ RETURN vle_array
+$$) AS (vle_array agtype);
+ vle_array
+-----------
+(0 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) = size(vle_array)
+ RETURN vle_array
+$$) AS (vle_array agtype);
+
vle_array
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+-- head
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN head(vle_array)
+$$) AS (head agtype);
+ head
+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE head(vle_array) = vle_array[0]
+ RETURN vle_array
+$$) AS (head agtype);
+
head
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE head(vle_array) = vle_array[size(vle_array) - size(vle_array)]
+ RETURN vle_array
+$$) AS (head agtype);
+
head
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE head(vle_array) = head([vle_array[0]])
+ RETURN vle_array LIMIT 1
+$$) AS (head agtype);
+ head
+-----------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+(1 row)
+
+-- last
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN last(vle_array)
+$$) AS (head agtype);
+ head
+---------------------------------------------------------------------------------------------------------------------------
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge
+ {"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE last(vle_array) = vle_array[0]
+ RETURN vle_array
+$$) AS (head agtype);
+ head
+-----------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+(4 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE last(vle_array) = vle_array[size(vle_array)-1]
+ RETURN vle_array
+$$) AS (head agtype);
+
head
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE last(vle_array) = head([vle_array[size(vle_array)-1]])
+ RETURN vle_array LIMIT 1
+$$) AS (head agtype);
+ head
+-----------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+(1 row)
+
+-- isEmpty
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty(vle_array)
+ RETURN vle_array
+$$) AS (head agtype);
+ head
+------
+(0 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty(vle_array) = false
+ RETURN vle_array
+$$) AS (head agtype);
+
head
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty(vle_array[0..0])
+ RETURN vle_array
+$$) AS (head agtype);
+
head
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty([vle_array[3]]) = false
+ RETURN vle_array
+$$) AS (head agtype);
+
head
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+(6 rows)
+
+-- reverse
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN reverse(vle_array)
+$$) as (u agtype);
+
u
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+(6 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE reverse(vle_array)[0] = last(vle_array)
+ RETURN reverse(vle_array)
+$$) as (u agtype);
+
u
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge, {"id": 1407374883553282,
"label": "e1", "end_id": 1125899906842626, "start_id": 1125899906842625,
"properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+(6 rows)
+
+-- IN operator
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[0] IN vle_array
+ RETURN vle_array
+$$) AS (a agtype);
+
a
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+(3 rows)
+
+-- access slice
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[0..1] = [vle_array[0]]
+ RETURN vle_array
+$$) AS (a agtype);
+
a
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge]
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+ [{"id": 1407374883553281, "label": "e1", "end_id": 1125899906842627,
"start_id": 1125899906842626, "properties": {}}::edge]
+(3 rows)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[1..2] = [last(vle_array)]
+ RETURN vle_array
+$$) AS (a agtype);
+
a
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 1407374883553282, "label": "e1", "end_id": 1125899906842626,
"start_id": 1125899906842625, "properties": {}}::edge, {"id": 1407374883553281,
"label": "e1", "end_id": 1125899906842627, "start_id": 1125899906842626,
"properties": {}}::edge]
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[0..1] = [vle_array[0], vle_array[1]]
+ RETURN vle_array
+$$) AS (a agtype);
+ a
+---
+(0 rows)
+
---
--- Fix: Segmentation fault when using specific names for tables #1124
---
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index 738606de..d5802712 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -1221,6 +1221,14 @@ $$) AS (size agtype);
SELECT * FROM cypher('expr', $$
RETURN size()
$$) AS (size agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array[0]) = 0
+ RETURN vle_array
+$$) AS (vle_array agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN size({id: 0, status:'it_will_fail'})
+$$) AS (size agtype);
-- head() of an array
SELECT * FROM cypher('expr', $$
RETURN head([1, 2, 3, 4, 5])
@@ -1235,6 +1243,9 @@ $$) AS (head agtype);
SELECT * FROM cypher('expr', $$
RETURN head(null)
$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN head([null, null])
+$$) AS (head agtype);
-- should fail
SELECT * FROM cypher('expr', $$
RETURN head(1234567890)
@@ -1242,6 +1253,13 @@ $$) AS (head agtype);
SELECT * FROM cypher('expr', $$
RETURN head()
$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN head(vle_array[0])
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN head({id: 0, status:'it_will_fail'})
+$$) AS (head agtype);
-- last()
SELECT * FROM cypher('expr', $$
RETURN last([1, 2, 3, 4, 5])
@@ -1256,6 +1274,9 @@ $$) AS (last agtype);
SELECT * FROM cypher('expr', $$
RETURN last(null)
$$) AS (last agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN last([null, null])
+$$) AS (last agtype);
-- should fail
SELECT * FROM cypher('expr', $$
RETURN last(1234567890)
@@ -1263,6 +1284,13 @@ $$) AS (last agtype);
SELECT * FROM cypher('expr', $$
RETURN last()
$$) AS (last agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN last(vle_array[0])
+$$) AS (last agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN last({id: 0, status:'it_will_fail'})
+$$) AS (last agtype);
-- properties()
SELECT * FROM cypher('expr', $$
MATCH (v) RETURN properties(v)
@@ -1644,6 +1672,13 @@ SELECT * FROM cypher('expr', $$
RETURN reverse()
$$) AS (results agtype);
SELECT * FROM age_reverse();
+SELECT * FROM cypher('expr', $$
+ MATCH (v)
+ RETURN reverse(v)
+$$) AS (results agtype);
+SELECT * FROM cypher('expr', $$
+ RETURN reverse({})
+$$) AS (results agtype);
--
-- toUpper() and toLower()
@@ -3184,7 +3219,130 @@ SELECT * FROM cypher('graph_395', $$ MATCH
(p:Project)-[:Has]->(t:Task)-[:Assign
WITH p, collect(task) AS tasks
WITH {pn: p.name, tasks:tasks} AS project
RETURN project $$) AS (p agtype);
+--
+-- issue 1044 - array functions not recognizing vpc
+--
+
+-- size
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) > 0
+ RETURN vle_array
+$$) AS (vle_array agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) > 1
+ RETURN vle_array
+$$) AS (vle_array agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) > 2
+ RETURN vle_array
+$$) AS (vle_array agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE size(vle_array) = size(vle_array)
+ RETURN vle_array
+$$) AS (vle_array agtype);
+-- head
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN head(vle_array)
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE head(vle_array) = vle_array[0]
+ RETURN vle_array
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE head(vle_array) = vle_array[size(vle_array) - size(vle_array)]
+ RETURN vle_array
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE head(vle_array) = head([vle_array[0]])
+ RETURN vle_array LIMIT 1
+$$) AS (head agtype);
+
+-- last
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN last(vle_array)
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE last(vle_array) = vle_array[0]
+ RETURN vle_array
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE last(vle_array) = vle_array[size(vle_array)-1]
+ RETURN vle_array
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE last(vle_array) = head([vle_array[size(vle_array)-1]])
+ RETURN vle_array LIMIT 1
+$$) AS (head agtype);
+
+-- isEmpty
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty(vle_array)
+ RETURN vle_array
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty(vle_array) = false
+ RETURN vle_array
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty(vle_array[0..0])
+ RETURN vle_array
+$$) AS (head agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE isEmpty([vle_array[3]]) = false
+ RETURN vle_array
+$$) AS (head agtype);
+
+-- reverse
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ RETURN reverse(vle_array)
+$$) as (u agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]-()
+ WHERE reverse(vle_array)[0] = last(vle_array)
+ RETURN reverse(vle_array)
+$$) as (u agtype);
+
+-- IN operator
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[0] IN vle_array
+ RETURN vle_array
+$$) AS (a agtype);
+
+-- access slice
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[0..1] = [vle_array[0]]
+ RETURN vle_array
+$$) AS (a agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[1..2] = [last(vle_array)]
+ RETURN vle_array
+$$) AS (a agtype);
+SELECT * FROM cypher('expr', $$
+ MATCH ()-[vle_array *]->()
+ WHERE vle_array[0..1] = [vle_array[0], vle_array[1]]
+ RETURN vle_array
+$$) AS (a agtype);
---
--- Fix: Segmentation fault when using specific names for tables #1124
---
diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c
index 2c5d3862..56ce5d82 100644
--- a/src/backend/parser/cypher_expr.c
+++ b/src/backend/parser/cypher_expr.c
@@ -505,21 +505,29 @@ static Node *transform_AEXPR_IN(cypher_parsestate
*cpstate, A_Expr *a)
bool useOr;
ListCell *l;
- /* Check for null arguments in the list to return NULL*/
if (!is_ag_node(a->rexpr, cypher_list))
{
- if (nodeTag(a->rexpr) == T_A_Const)
- {
- A_Const *r_a_const = (A_Const*)a->rexpr;
- if (r_a_const->val.type == T_Null)
- {
- return (Node *)makeConst(AGTYPEOID, -1, InvalidOid, -1,
- (Datum)NULL, true, false);
- }
- }
+ /*
+ * We need to build a function call here if the rexpr is already
+ * tranformed. It can be already tranformed cypher_list as columnref.
+ */
+ Oid func_in_oid;
+ FuncExpr *func_in_expr;
+ List *args = NIL;
+
+ args = lappend(args, transform_cypher_expr_recurse(cpstate, a->rexpr));
+ args = lappend(args, transform_cypher_expr_recurse(cpstate, a->lexpr));
+
+ /* get the agtype_in_operator function */
+ func_in_oid = get_ag_func_oid("agtype_in_operator", 2, AGTYPEOID,
+ AGTYPEOID);
+
+ func_in_expr = makeFuncExpr(func_in_oid, AGTYPEOID, args, InvalidOid,
+ InvalidOid, COERCE_EXPLICIT_CALL);
+
+ func_in_expr->location = exprLocation(a->lexpr);
- ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("object of IN must be a list")));
+ return (Node *)func_in_expr;
}
Assert(is_ag_node(a->rexpr, cypher_list));
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 45a626f8..174c7786 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -3928,7 +3928,8 @@ Datum agtype_access_slice(PG_FUNCTION_ARGS)
agtype_value *lidx_value = NULL;
agtype_value *uidx_value = NULL;
agtype_in_state result;
- agtype *array = NULL;
+ agtype *agt_array = NULL;
+ agtype_value *agtv_array = NULL;
int64 upper_index = 0;
int64 lower_index = 0;
uint32 array_size = 0;
@@ -3948,15 +3949,26 @@ Datum agtype_access_slice(PG_FUNCTION_ARGS)
}
/* get the array parameter and verify that it is a list */
- array = AG_GET_ARG_AGTYPE_P(0);
- if (!AGT_ROOT_IS_ARRAY(array) || AGT_ROOT_IS_SCALAR(array))
+ agt_array = AG_GET_ARG_AGTYPE_P(0);
+
+ if ((!AGT_ROOT_IS_ARRAY(agt_array) && !AGT_ROOT_IS_VPC(agt_array)) ||
AGT_ROOT_IS_SCALAR(agt_array))
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("slice must access a list")));
}
- /* get its size */
- array_size = AGT_ROOT_COUNT(array);
+ /* If we have a vpc, decode it and get AGTV_ARRAY agtype_value */
+ if (AGT_ROOT_IS_VPC(agt_array))
+ {
+ agtv_array = agtv_materialize_vle_edges(agt_array);
+
+ /* get the size of array */
+ array_size = agtv_array->val.array.num_elems;
+ }
+ else
+ {
+ array_size = AGT_ROOT_COUNT(agt_array);
+ }
/* if we don't have a lower bound, make it 0 */
if (PG_ARGISNULL(1))
@@ -4049,11 +4061,23 @@ Datum agtype_access_slice(PG_FUNCTION_ARGS)
result.res = push_agtype_value(&result.parse_state, WAGT_BEGIN_ARRAY,
NULL);
- /* get array elements */
- for (i = lower_index; i < upper_index; i++)
+ /* if we have agtype_value, we need to iterate through the array */
+ if (agtv_array)
{
- result.res = push_agtype_value(&result.parse_state, WAGT_ELEM,
- get_ith_agtype_value_from_container(&array->root, i));
+ for (i = lower_index; i < upper_index; i++)
+ {
+ result.res = push_agtype_value(&result.parse_state, WAGT_ELEM,
+ &agtv_array->val.array.elems[i]);
+ }
+ }
+ else
+ {
+ /* get array elements from agtype_container */
+ for (i = lower_index; i < upper_index; i++)
+ {
+ result.res = push_agtype_value(&result.parse_state, WAGT_ELEM,
+ get_ith_agtype_value_from_container(&agt_array->root, i));
+ }
}
result.res = push_agtype_value(&result.parse_state, WAGT_END_ARRAY, NULL);
@@ -4067,78 +4091,145 @@ PG_FUNCTION_INFO_V1(agtype_in_operator);
*/
Datum agtype_in_operator(PG_FUNCTION_ARGS)
{
- agtype *agt_array, *agt_item;
+ agtype *agt_arg, *agt_item;
agtype_iterator *it_array, *it_item;
- agtype_value agtv_item, agtv_elem;
+ agtype_value *agtv_arg, agtv_item, agtv_elem;
uint32 array_size = 0;
bool result = false;
uint32 i = 0;
/* return null if the array is null */
if (PG_ARGISNULL(0))
+ {
PG_RETURN_NULL();
+ }
/* get the array parameter and verify that it is a list */
- agt_array = AG_GET_ARG_AGTYPE_P(0);
- if (!AGT_ROOT_IS_ARRAY(agt_array))
- ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("object of IN must be a list")));
+ agt_arg = AG_GET_ARG_AGTYPE_P(0);
- /* init array iterator */
- it_array = agtype_iterator_init(&agt_array->root);
- /* open array container */
- agtype_iterator_next(&it_array, &agtv_elem, false);
- /* check for an array scalar value */
- if (agtv_elem.type == AGTV_ARRAY && agtv_elem.val.array.raw_scalar)
+ if ((!AGT_ROOT_IS_ARRAY(agt_arg) && !AGT_ROOT_IS_VPC(agt_arg)) ||
AGT_ROOT_IS_SCALAR(agt_arg))
{
- agtype_iterator_next(&it_array, &agtv_elem, false);
- /* check for AGTYPE NULL */
- if (agtv_elem.type == AGTV_NULL)
- PG_RETURN_NULL();
- /* if it is a scalar, but not AGTV_NULL, error out */
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("object of IN must be a list")));
}
+ /* If we have vpc as arg, get the agtype_value AGTV_ARRAY of edges */
+ if (AGT_ROOT_IS_VPC(agt_arg))
+ {
+ agtv_arg = agtv_materialize_vle_edges(agt_arg);
+ array_size = agtv_arg->val.array.num_elems;
+
+ /* return null if the item to find is null */
+ if (PG_ARGISNULL(1))
+ {
+ PG_RETURN_NULL();
+ }
+ /* get the item to search for */
+ agt_item = AG_GET_ARG_AGTYPE_P(1);
- array_size = AGT_ROOT_COUNT(agt_array);
+ /* init item iterator */
+ it_item = agtype_iterator_init(&agt_item->root);
- /* return null if the item to find is null */
- if (PG_ARGISNULL(1))
- PG_RETURN_NULL();
- /* get the item to search for */
- agt_item = AG_GET_ARG_AGTYPE_P(1);
+ /* get value of item */
+ agtype_iterator_next(&it_item, &agtv_item, false);
+ if (agtv_item.type == AGTV_ARRAY && agtv_item.val.array.raw_scalar)
+ {
+ agtype_iterator_next(&it_item, &agtv_item, false);
+ /* check for AGTYPE NULL */
+ if (agtv_item.type == AGTV_NULL)
+ {
+ PG_RETURN_NULL();
+ }
+ }
- /* init item iterator */
- it_item = agtype_iterator_init(&agt_item->root);
+ /* iterate through the array, but stop if we find it */
+ for (i = 0; i < array_size && !result; i++)
+ {
+ agtv_elem = agtv_arg->val.array.elems[i];
- /* get value of item */
- agtype_iterator_next(&it_item, &agtv_item, false);
- if (agtv_item.type == AGTV_ARRAY && agtv_item.val.array.raw_scalar)
+ /* if both are containers, compare containers */
+ if (!IS_A_AGTYPE_SCALAR(&agtv_item) &&
!IS_A_AGTYPE_SCALAR(&agtv_elem))
+ {
+ result = (compare_agtype_containers_orderability(
+ &agt_item->root, agtv_elem.val.binary.data) == 0);
+ }
+ /* if both are scalars and of the same type, compare scalars */
+ else if (IS_A_AGTYPE_SCALAR(&agtv_item) &&
+ IS_A_AGTYPE_SCALAR(&agtv_elem) &&
+ agtv_item.type == agtv_elem.type)
+ {
+ result = (compare_agtype_scalar_values(&agtv_item, &agtv_elem)
==
+ 0);
+ }
+ }
+ }
+ /* Else we need to iterate agtype_container */
+ else
{
- agtype_iterator_next(&it_item, &agtv_item, false);
- /* check for AGTYPE NULL */
- if (agtv_item.type == AGTV_NULL)
+ /* init array iterator */
+ it_array = agtype_iterator_init(&agt_arg->root);
+ /* open array container */
+ agtype_iterator_next(&it_array, &agtv_elem, false);
+ /* check for an array scalar value */
+ if (agtv_elem.type == AGTV_ARRAY && agtv_elem.val.array.raw_scalar)
+ {
+ agtype_iterator_next(&it_array, &agtv_elem, false);
+ /* check for AGTYPE NULL */
+ if (agtv_elem.type == AGTV_NULL)
+ {
+ PG_RETURN_NULL();
+ }
+ /* if it is a scalar, but not AGTV_NULL, error out */
+ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("object of IN must be a list")));
+ }
+
+ array_size = AGT_ROOT_COUNT(agt_arg);
+
+ /* return null if the item to find is null */
+ if (PG_ARGISNULL(1))
+ {
PG_RETURN_NULL();
- }
+ }
+ /* get the item to search for */
+ agt_item = AG_GET_ARG_AGTYPE_P(1);
- /* iterate through the array, but stop if we find it */
- for (i = 0; i < array_size && !result; i++)
- {
- /* get next element */
- agtype_iterator_next(&it_array, &agtv_elem, true);
- /* if both are containers, compare containers */
- if (!IS_A_AGTYPE_SCALAR(&agtv_item) && !IS_A_AGTYPE_SCALAR(&agtv_elem))
+ /* init item iterator */
+ it_item = agtype_iterator_init(&agt_item->root);
+
+ /* get value of item */
+ agtype_iterator_next(&it_item, &agtv_item, false);
+ if (agtv_item.type == AGTV_ARRAY && agtv_item.val.array.raw_scalar)
{
- result = (compare_agtype_containers_orderability(
- &agt_item->root, agtv_elem.val.binary.data) == 0);
+ agtype_iterator_next(&it_item, &agtv_item, false);
+ /* check for AGTYPE NULL */
+ if (agtv_item.type == AGTV_NULL)
+ {
+ PG_RETURN_NULL();
+ }
}
- /* if both are scalars and of the same type, compare scalars */
- else if (IS_A_AGTYPE_SCALAR(&agtv_item) &&
- IS_A_AGTYPE_SCALAR(&agtv_elem) &&
- agtv_item.type == agtv_elem.type)
- result = (compare_agtype_scalar_values(&agtv_item, &agtv_elem) ==
- 0);
+
+ /* iterate through the array, but stop if we find it */
+ for (i = 0; i < array_size && !result; i++)
+ {
+ /* get next element */
+ agtype_iterator_next(&it_array, &agtv_elem, true);
+ /* if both are containers, compare containers */
+ if (!IS_A_AGTYPE_SCALAR(&agtv_item) &&
!IS_A_AGTYPE_SCALAR(&agtv_elem))
+ {
+ result = (compare_agtype_containers_orderability(
+ &agt_item->root, agtv_elem.val.binary.data) == 0);
+ }
+ /* if both are scalars and of the same type, compare scalars */
+ else if (IS_A_AGTYPE_SCALAR(&agtv_item) &&
+ IS_A_AGTYPE_SCALAR(&agtv_elem) &&
+ agtv_item.type == agtv_elem.type)
+ {
+ result = (compare_agtype_scalar_values(&agtv_item, &agtv_elem)
==
+ 0);
+ }
+ }
}
+
return boolean_to_agtype(result);
}
@@ -5266,31 +5357,58 @@ PG_FUNCTION_INFO_V1(age_head);
Datum age_head(PG_FUNCTION_ARGS)
{
agtype *agt_arg = NULL;
+ agtype_value *agtv_arg = NULL;
agtype_value *agtv_result = NULL;
- int count;
/* 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))
+ if ((!AGT_ROOT_IS_ARRAY(agt_arg) && !AGT_ROOT_IS_VPC(agt_arg)) ||
AGT_ROOT_IS_SCALAR(agt_arg))
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("head() argument must resolve to a list or
null")));
+ }
- count = AGT_ROOT_COUNT(agt_arg);
+ /*
+ * If we have a vpc, materialize the edges to get AGTV_ARRAY
+ * agtype_value, process it and return the result.
+ */
+ if (AGT_ROOT_IS_VPC(agt_arg))
+ {
+ agtv_arg = agtv_materialize_vle_edges(agt_arg);
- /* if we have an empty list, return a null */
- if (count == 0)
- PG_RETURN_NULL();
+ /* if we have an empty list, return a null */
+ if (agtv_arg->val.array.num_elems == 0)
+ {
+ PG_RETURN_NULL();
+ }
+
+ /* get the first element of the array */
+ agtv_result = &agtv_arg->val.array.elems[0];
+ }
+ else
+ {
+ /* if we have an empty list, return a null */
+ if (AGT_ROOT_COUNT(agt_arg) == 0)
+ {
+ PG_RETURN_NULL();
+ }
- /* get the first element of the array */
- agtv_result = get_ith_agtype_value_from_container(&agt_arg->root, 0);
+ /* get the first element of the array */
+ agtv_result = get_ith_agtype_value_from_container(&agt_arg->root, 0);
+ }
/* if it is AGTV_NULL, return null */
if (agtv_result->type == AGTV_NULL)
+ {
PG_RETURN_NULL();
+ }
PG_RETURN_POINTER(agtype_value_to_agtype(agtv_result));
}
@@ -5300,31 +5418,63 @@ PG_FUNCTION_INFO_V1(age_last);
Datum age_last(PG_FUNCTION_ARGS)
{
agtype *agt_arg = NULL;
+ agtype_value *agtv_arg = NULL;
agtype_value *agtv_result = NULL;
- int count;
+ int size;
/* 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))
+ if ((!AGT_ROOT_IS_ARRAY(agt_arg) && !AGT_ROOT_IS_VPC(agt_arg)) ||
AGT_ROOT_IS_SCALAR(agt_arg))
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("last() argument must resolve to a list or
null")));
+ }
- count = AGT_ROOT_COUNT(agt_arg);
+ /*
+ * If we have a vpc, materialize the edges to get AGTV_ARRAY
+ * agtype_value, process it and return the result.
+ */
+ if (AGT_ROOT_IS_VPC(agt_arg))
+ {
+ agtv_arg = agtv_materialize_vle_edges(agt_arg);
- /* if we have an empty list, return null */
- if (count == 0)
- PG_RETURN_NULL();
+ size = agtv_arg->val.array.num_elems;
- /* get the last element of the array */
- agtv_result = get_ith_agtype_value_from_container(&agt_arg->root, count
-1);
+ /* if we have an empty list, return a null */
+ if (size == 0)
+ {
+ PG_RETURN_NULL();
+ }
+
+ /* get the first element of the array */
+ agtv_result = &agtv_arg->val.array.elems[size-1];
+ }
+ else
+ {
+ size = AGT_ROOT_COUNT(agt_arg);
+
+ /* if we have an empty list, return a null */
+ if (size == 0)
+ {
+ PG_RETURN_NULL();
+ }
+
+ /* get the first element of the array */
+ agtv_result = get_ith_agtype_value_from_container(&agt_arg->root,
size-1);
+ }
/* if it is AGTV_NULL, return null */
if (agtv_result->type == AGTV_NULL)
+ {
PG_RETURN_NULL();
+ }
PG_RETURN_POINTER(agtype_value_to_agtype(agtv_result));
}
@@ -6252,12 +6402,16 @@ Datum age_size(PG_FUNCTION_ARGS)
/* check number of args */
if (nargs > 1)
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("size() only supports one argument")));
+ }
/* check for null */
if (nargs < 0 || nulls[0])
+ {
PG_RETURN_NULL();
+ }
/*
* size() supports cstring, text, or the agtype string or list input
@@ -6278,31 +6432,45 @@ Datum age_size(PG_FUNCTION_ARGS)
else if (type == AGTYPEOID)
{
agtype *agt_arg;
+ agtype_value *agtv_value;
/* get the agtype argument */
agt_arg = DATUM_GET_AGTYPE_P(arg);
if (AGT_ROOT_IS_SCALAR(agt_arg))
{
- agtype_value *agtv_value;
-
agtv_value = get_ith_agtype_value_from_container(&agt_arg->root,
0);
if (agtv_value->type == AGTV_STRING)
+ {
result = agtv_value->val.string.len;
+ }
else
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("size() unsupported
argument")));
+ }
+ }
+ else if (AGT_ROOT_IS_VPC(agt_arg))
+ {
+ agtv_value = agtv_materialize_vle_edges(agt_arg);
+ result = agtv_value->val.array.num_elems;
}
else if (AGT_ROOT_IS_ARRAY(agt_arg))
+ {
result = AGT_ROOT_COUNT(agt_arg);
+ }
else
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("size() unsupported argument")));
+ }
}
else
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("size() unsupported argument")));
+ }
/* build the result */
agtv_result.type = AGTV_INTEGER;
@@ -6426,14 +6594,13 @@ Datum age_isempty(PG_FUNCTION_ARGS)
else if (type == AGTYPEOID)
{
agtype *agt_arg;
+ agtype_value *agtv_value;
/* get the agtype argument */
agt_arg = DATUM_GET_AGTYPE_P(arg);
if (AGT_ROOT_IS_SCALAR(agt_arg))
{
- agtype_value *agtv_value;
-
agtv_value = get_ith_agtype_value_from_container(&agt_arg->root,
0);
if (agtv_value->type == AGTV_STRING)
@@ -6446,6 +6613,11 @@ Datum age_isempty(PG_FUNCTION_ARGS)
errmsg("isEmpty() unsupported
argument, expected a List, Map, or String")));
}
}
+ else if (AGT_ROOT_IS_VPC(agt_arg))
+ {
+ agtv_value = agtv_materialize_vle_edges(agt_arg);
+ result = agtv_value->val.array.num_elems;
+ }
else if (AGT_ROOT_IS_ARRAY(agt_arg))
{
result = AGT_ROOT_COUNT(agt_arg);
@@ -6824,12 +6996,16 @@ Datum age_reverse(PG_FUNCTION_ARGS)
/* check number of args */
if (nargs > 1)
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("reverse() only supports one argument")));
+ }
/* check for null */
if (nargs < 0 || nulls[0])
+ {
PG_RETURN_NULL();
+ }
/* reverse() supports text, cstring, or the agtype string input */
arg = args[0];
@@ -6838,18 +7014,25 @@ Datum age_reverse(PG_FUNCTION_ARGS)
if (type != AGTYPEOID)
{
if (type == CSTRINGOID)
+ {
text_string = cstring_to_text(DatumGetCString(arg));
+ }
else if (type == TEXTOID)
+ {
text_string = DatumGetTextPP(arg);
+ }
else
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("reverse() unsupported argument type %d",
type)));
+ }
}
else
{
agtype *agt_arg = NULL;
agtype_value *agtv_value = NULL;
+ agtype_in_state result;
agtype_parse_state *parse_state = NULL;
agtype_value elem = {0};
agtype_iterator *it = NULL;
@@ -6861,7 +7044,28 @@ Datum age_reverse(PG_FUNCTION_ARGS)
/* get the agtype argument */
agt_arg = DATUM_GET_AGTYPE_P(arg);
- if (!AGT_ROOT_IS_SCALAR(agt_arg))
+ if (AGT_ROOT_IS_SCALAR(agt_arg))
+ {
+ agtv_value = get_ith_agtype_value_from_container(&agt_arg->root,
0);
+
+ /* check for agtype null */
+ if (agtv_value->type == AGTV_NULL)
+ {
+ PG_RETURN_NULL();
+ }
+ if (agtv_value->type == AGTV_STRING)
+ {
+ text_string =
cstring_to_text_with_len(agtv_value->val.string.val,
+
agtv_value->val.string.len);
+ }
+ else
+ {
+ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("reverse() unsupported argument agtype
%d",
+ agtv_value->type)));
+ }
+ }
+ else if (AGT_ROOT_IS_ARRAY(agt_arg))
{
agtv_value = push_agtype_value(&parse_state, WAGT_BEGIN_ARRAY,
NULL);
@@ -6892,19 +7096,32 @@ Datum age_reverse(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(agtype_value_to_agtype(agtv_value));
}
+ else if (AGT_ROOT_IS_VPC(agt_arg))
+ {
+ elems = agtv_materialize_vle_edges(agt_arg);
+ num_elems = elems->val.array.num_elems;
- agtv_value = get_ith_agtype_value_from_container(&agt_arg->root, 0);
+ /* build our result array */
+ memset(&result, 0, sizeof(agtype_in_state));
- /* check for agtype null */
- if (agtv_value->type == AGTV_NULL)
- PG_RETURN_NULL();
- if (agtv_value->type == AGTV_STRING)
- text_string = cstring_to_text_with_len(agtv_value->val.string.val,
- agtv_value->val.string.len);
+ result.res = push_agtype_value(&result.parse_state,
+ WAGT_BEGIN_ARRAY, NULL);
+
+ for (i = num_elems-1; i >= 0; i--)
+ {
+ result.res = push_agtype_value(&result.parse_state, WAGT_ELEM,
+ &elems->val.array.elems[i]);
+ }
+
+ result.res = push_agtype_value(&result.parse_state,
WAGT_END_ARRAY, NULL);
+
+ PG_RETURN_POINTER(agtype_value_to_agtype(result.res));
+ }
else
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("reverse() unsupported argument agtype %d",
- agtv_value->type)));
+ errmsg("reverse() unsupported argument agtype")));
+ }
}
/*
@@ -6920,7 +7137,9 @@ Datum age_reverse(PG_FUNCTION_ARGS)
/* if we have an empty string, return null */
if (string_len == 0)
+ {
PG_RETURN_NULL();
+ }
/* build the result */
agtv_result.type = AGTV_STRING;
diff --git a/src/include/utils/agtype.h b/src/include/utils/agtype.h
index 75712dd7..d4c88b98 100644
--- a/src/include/utils/agtype.h
+++ b/src/include/utils/agtype.h
@@ -294,6 +294,8 @@ typedef struct
((*(uint32 *)VARDATA(agtp_) & AGT_FBINARY) != 0)
#define AGT_ROOT_BINARY_FLAGS(agtp_) \
(*(uint32 *)VARDATA(agtp_) & AGT_FBINARY_MASK)
+#define AGT_ROOT_IS_VPC(agtp_) \
+ (AGT_ROOT_IS_BINARY(agtp_) && (AGT_ROOT_BINARY_FLAGS(agtp_) ==
AGT_FBINARY_TYPE_VLE_PATH))
/* values for the AGTYPE header field to denote the stored data type */
#define AGT_HEADER_INTEGER 0x00000000