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

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


The following commit(s) were added to refs/heads/master by this push:
     new 7cdd0eff Add checks for array functions to recognize and decode VPC 
(#1064)
7cdd0eff is described below

commit 7cdd0effaf0c29c704a46ab216cfc9748f75a5dd
Author: Muhammad Taha Naveed <[email protected]>
AuthorDate: Wed Jan 3 02:55:57 2024 +0500

    Add checks for array functions to recognize and decode VPC (#1064)
    
    * 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.
---
 regress/expected/expr.out        | 349 +++++++++++++++++++++++++++++++++-
 regress/sql/expr.sql             | 158 ++++++++++++++++
 src/backend/parser/cypher_expr.c |  31 ++--
 src/backend/utils/adt/agtype.c   | 391 ++++++++++++++++++++++++++++++---------
 src/include/utils/agtype.h       |   2 +
 5 files changed, 830 insertions(+), 101 deletions(-)

diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index 651035eb..cc582ccc 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 dade1e08..f110e8f5 100644
--- a/src/backend/parser/cypher_expr.c
+++ b/src/backend/parser/cypher_expr.c
@@ -517,20 +517,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->isnull == true)
-            {
-                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 ce0d1bb0..b91e5174 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -3936,7 +3936,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;
@@ -3956,15 +3957,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))
@@ -4057,11 +4069,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);
@@ -4075,78 +4099,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);
 }
 
@@ -5284,31 +5375,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));
 }
@@ -5318,31 +5436,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));
 }
@@ -6291,12 +6441,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
@@ -6317,31 +6471,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;
@@ -6465,14 +6633,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)
@@ -6485,6 +6652,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);
@@ -6874,12 +7046,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];
@@ -6888,18 +7064,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;
@@ -6911,7 +7094,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);
 
@@ -6942,19 +7146,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")));
+        }
     }
 
     /*
@@ -6970,7 +7187,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 18b01f6e..62150372 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

Reply via email to