You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by jg...@apache.org on 2022/07/13 15:55:24 UTC
[age] branch master updated: Fix issue #240 - negative array bounds - addendum
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 5ded59f Fix issue #240 - negative array bounds - addendum
5ded59f is described below
commit 5ded59fca7b43612abb9baf50cf2905deb349ebb
Author: John Gemignani <jr...@gmail.com>
AuthorDate: Tue Jul 12 15:51:56 2022 -0700
Fix issue #240 - negative array bounds - addendum
Fixed github issue #240 - negative array bounds - addendum.
There was found to be an issue with the transform_A_Indirection
function. Previous work on the function removed a few important
lines. This caused it to improperly transform nested indirections.
These lines were added back in.
Additionally, since the previous work on transform_A_Indirection,
some new functionality was added to transform_ColumnRef. This
allowed the removal of some unnecessary code as well.
Added regression tests to cover nested access and slice operations.
---
regress/expected/expr.out | 111 ++++++++++++++++++++++++++++
regress/sql/expr.sql | 24 +++++++
src/backend/parser/cypher_expr.c | 90 ++++++++---------------
src/backend/utils/adt/agtype.c | 151 +++++++++++++++++++++++++++++++--------
4 files changed, 287 insertions(+), 89 deletions(-)
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index 61f4816..5f28e36 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -405,6 +405,117 @@ $$RETURN [0][0..-2147483649]$$) as r(a agtype);
[]
(1 row)
+-- access and slice operators nested
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[0] $$) as (results agtype);
+ results
+---------
+ 0
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2] $$) as (results agtype);
+ results
+-----------
+ [2, 3, 4]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-1] $$) as (results agtype);
+ results
+---------
+ 9
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2][-2] $$) as (results agtype);
+ results
+---------
+ 3
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2][-2..] $$) as (results agtype);
+ results
+---------
+ [3, 4]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..] $$) as (results agtype);
+ results
+----------------
+ [[6, 7, 8], 9]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-1..] $$) as (results agtype);
+ results
+---------
+ [9]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][0] $$) as (results agtype);
+ results
+---------
+ 9
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-1] $$) as (results agtype);
+ results
+---------
+ 9
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-2..-1] $$) as (results agtype);
+ results
+-------------
+ [[6, 7, 8]]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2] $$) as (results agtype);
+ results
+----------------
+ [[2, 3, 4], 5]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][-2] $$) as (results agtype);
+ results
+-----------
+ [2, 3, 4]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][0] $$) as (results agtype);
+ results
+-----------
+ [2, 3, 4]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][-2][-2..] $$) as (results agtype);
+ results
+---------
+ [3, 4]
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][-2][-2..][0] $$) as (results agtype);
+ results
+---------
+ 3
+(1 row)
+
+-- empty list
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-2..-2] $$) as (results agtype);
+ results
+---------
+ []
+(1 row)
+
+-- should return null
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2][3] $$) as (results agtype);
+ results
+---------
+
+(1 row)
+
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-2] $$) as (results agtype);
+ results
+---------
+
+(1 row)
+
--
-- String operators
--
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index c8ad89d..7fe904f 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -192,6 +192,30 @@ $$RETURN 0[[0]..[1]]$$) as r(a agtype);
SELECT * from cypher('expr',
$$RETURN [0][0..-2147483649]$$) as r(a agtype);
+-- access and slice operators nested
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[0] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-1] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2][-2] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2][-2..] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-1..] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][0] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-1] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-2..-1] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][-2] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][0] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][-2][-2..] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-4..-2][-2][-2..][0] $$) as (results agtype);
+
+-- empty list
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-2..-2] $$) as (results agtype);
+
+-- should return null
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[2][3] $$) as (results agtype);
+SELECT * from cypher('expr', $$ WITH [0, 1, [2, 3, 4], 5, [6, 7, 8], 9] as l RETURN l[-2..][-1..][-2] $$) as (results agtype);
+
--
-- String operators
--
diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c
index 914ab29..cb43788 100644
--- a/src/backend/parser/cypher_expr.c
+++ b/src/backend/parser/cypher_expr.c
@@ -94,8 +94,7 @@ static Node *transform_FuncCall(cypher_parsestate *cpstate, FuncCall *fn);
static Node *transform_WholeRowRef(ParseState *pstate, RangeTblEntry *rte,
int location);
static ArrayExpr *make_agtype_array_expr(List *args);
-static Node *transform_column_ref_for_indirection(cypher_parsestate *cpstate,
- ColumnRef *cr);
+
/* transform a cypher expression */
Node *transform_cypher_expr(cypher_parsestate *cpstate, Node *expr,
ParseExprKind expr_kind)
@@ -703,57 +702,15 @@ static ArrayExpr *make_agtype_array_expr(List *args)
return newa;
}
-/*
- * Transforms a column ref for indirection. Try to find the rte that the
- * columnRef is references and pass the properties of that rte as what the
- * columnRef is referencing. Otherwise, reference the Var
- */
-static Node *transform_column_ref_for_indirection(cypher_parsestate *cpstate,
- ColumnRef *cr)
-{
- ParseState *pstate = (ParseState *)cpstate;
- RangeTblEntry *rte = NULL;
- Node *field1 = linitial(cr->fields);
- char *relname = NULL;
- Node *node = NULL;
-
- Assert(IsA(field1, String));
- relname = strVal(field1);
-
- // locate the referenced RTE
- rte = find_rte(cpstate, relname);
- if (rte == NULL)
- {
- /*
- * This column ref is referencing something that was created in
- * a previous query and is a variable.
- */
- return transform_cypher_expr_recurse(cpstate, (Node *)cr);
- }
-
- // try to identify the properties column of the RTE
- node = scanRTEForColumn(pstate, rte, "properties", cr->location, 0, NULL);
-
- if (node == NULL)
- {
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("could not find rte for %s", relname)));
-
- }
-
- return node;
-}
-
static Node *transform_A_Indirection(cypher_parsestate *cpstate,
A_Indirection *a_ind)
{
int location;
- ListCell *lc;
- Node *ind_arg_expr;
+ ListCell *lc = NULL;
+ Node *ind_arg_expr = NULL;
FuncExpr *func_expr = NULL;
- Oid func_access_oid;
- Oid func_slice_oid;
+ Oid func_access_oid = InvalidOid;
+ Oid func_slice_oid = InvalidOid;
List *args = NIL;
bool is_access = false;
@@ -766,20 +723,16 @@ static Node *transform_A_Indirection(cypher_parsestate *cpstate,
func_slice_oid = get_ag_func_oid("agtype_access_slice", 3, AGTYPEOID,
AGTYPEOID, AGTYPEOID);
- if (IsA(a_ind->arg, ColumnRef))
- {
- ColumnRef *cr = (ColumnRef *)a_ind->arg;
-
- ind_arg_expr = transform_column_ref_for_indirection(cpstate, cr);
- }
- else
- {
- ind_arg_expr = transform_cypher_expr_recurse(cpstate, a_ind->arg);
- }
+ /* transform indirection argument expression */
+ ind_arg_expr = transform_cypher_expr_recurse(cpstate, a_ind->arg);
+ /* get the location of the expression */
location = exprLocation(ind_arg_expr);
+ /* add the expression as the first entry */
args = lappend(args, ind_arg_expr);
+
+ /* iterate through the indirections */
foreach (lc, a_ind->indirection)
{
Node *node = lfirst(lc);
@@ -799,12 +752,21 @@ static Node *transform_A_Indirection(cypher_parsestate *cpstate,
InvalidOid, InvalidOid,
COERCE_EXPLICIT_CALL);
+ func_expr->funcvariadic = true;
+ func_expr->location = location;
+
+ /*
+ * The result of this function is the input to the next access
+ * or slice operator. So we need to start out with a new arg
+ * list with this function expression.
+ */
+ args = lappend(NIL, func_expr);
+
/* we are no longer working on an access */
is_access = false;
- func_expr->funcvariadic = true;
-
}
+
/* add slice bounds to args */
if (!indices->lidx)
{
@@ -832,11 +794,18 @@ static Node *transform_A_Indirection(cypher_parsestate *cpstate,
node = transform_cypher_expr_recurse(cpstate, indices->uidx);
}
args = lappend(args, node);
+
/* wrap and close it */
func_expr = makeFuncExpr(func_slice_oid, AGTYPEOID, args,
InvalidOid, InvalidOid,
COERCE_EXPLICIT_CALL);
func_expr->location = location;
+
+ /*
+ * The result of this function is the input to the next access
+ * or slice operator. So we need to start out with a new arg
+ * list with this function expression.
+ */
args = lappend(NIL, func_expr);
}
/* is this a string or index?*/
@@ -844,6 +813,7 @@ static Node *transform_A_Indirection(cypher_parsestate *cpstate,
{
/* we are working on an access */
is_access = true;
+
/* is this an index? */
if (IsA(node, A_Indices))
{
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 52d72bf..908f388 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -512,9 +512,11 @@ static void agtype_typecast_object(agtype_in_state *state, char *annotation)
last_updated_value->type = AGTV_VERTEX;
}
else
+ {
ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("object is not a vertex")));
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("object is not a vertex")));
+ }
}
/* check for a cast to an edge */
@@ -529,15 +531,19 @@ static void agtype_typecast_object(agtype_in_state *state, char *annotation)
last_updated_value->type = AGTV_EDGE;
}
else
+ {
ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("object is not a edge")));
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("object is not a edge")));
+ }
}
/* otherwise this isn't a supported typecast */
else
+ {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid annotation value for object")));
+ }
}
/* function to handle array typecasts */
@@ -582,17 +588,19 @@ static void agtype_typecast_array(agtype_in_state *state, char *annotation)
last_updated_value->type = AGTV_PATH;
}
else
+ {
ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("array is not a valid path")));
-
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("array is not a valid path")));
+ }
}
/* otherwise this isn't a supported typecast */
else
+ {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid annotation value for object")));
-
+ }
}
/* helper function to check if an object fits a vertex */
@@ -609,7 +617,9 @@ static bool is_object_vertex(agtype_value *agtv)
/* we need 3 pairs for a vertex */
if (agtv->val.object.num_pairs != 3)
+ {
return false;
+ }
/* iterate through all pairs */
for (i = 0; i < agtv->val.object.num_pairs; i++)
@@ -626,20 +636,28 @@ static bool is_object_vertex(agtype_value *agtv)
if (key_len == 2 &&
pg_strncasecmp(key_val, "id", key_len) == 0 &&
value->type == AGTV_INTEGER)
+ {
has_id = true;
+ }
/* check for a label of type string */
else if (key_len == 5 &&
- pg_strncasecmp(key_val, "label", key_len) == 0 &&
- value->type == AGTV_STRING)
+ pg_strncasecmp(key_val, "label", key_len) == 0 &&
+ value->type == AGTV_STRING)
+ {
has_label = true;
+ }
/* check for properties of type object */
else if (key_len == 10 &&
- pg_strncasecmp(key_val, "properties", key_len) == 0 &&
- value->type == AGTV_OBJECT)
+ pg_strncasecmp(key_val, "properties", key_len) == 0 &&
+ value->type == AGTV_OBJECT)
+ {
has_properties = true;
+ }
/* if it gets to this point, it can't be a vertex */
else
+ {
return false;
+ }
}
return (has_id && has_label && has_properties);
}
@@ -660,7 +678,9 @@ static bool is_object_edge(agtype_value *agtv)
/* we need 5 pairs for an edge */
if (agtv->val.object.num_pairs != 5)
+ {
return false;
+ }
/* iterate through the pairs */
for (i = 0; i < agtv->val.object.num_pairs; i++)
@@ -677,30 +697,42 @@ static bool is_object_edge(agtype_value *agtv)
if (key_len == 2 &&
pg_strncasecmp(key_val, "id", key_len) == 0 &&
value->type == AGTV_INTEGER)
+ {
has_id = true;
+ }
/* check for a label of type string */
else if (key_len == 5 &&
- pg_strncasecmp(key_val, "label", key_len) == 0 &&
- value->type == AGTV_STRING)
+ pg_strncasecmp(key_val, "label", key_len) == 0 &&
+ value->type == AGTV_STRING)
+ {
has_label = true;
+ }
/* check for properties of type object */
else if (key_len == 10 &&
- pg_strncasecmp(key_val, "properties", key_len) == 0 &&
- value->type == AGTV_OBJECT)
+ pg_strncasecmp(key_val, "properties", key_len) == 0 &&
+ value->type == AGTV_OBJECT)
+ {
has_properties = true;
+ }
/* check for a start_id of type integer */
else if (key_len == 8 &&
- pg_strncasecmp(key_val, "start_id", key_len) == 0 &&
- value->type == AGTV_INTEGER)
+ pg_strncasecmp(key_val, "start_id", key_len) == 0 &&
+ value->type == AGTV_INTEGER)
+ {
has_start_id = true;
+ }
/* check for an end_id of type integer */
else if (key_len == 6 &&
- pg_strncasecmp(key_val, "end_id", key_len) == 0 &&
- value->type == AGTV_INTEGER)
+ pg_strncasecmp(key_val, "end_id", key_len) == 0 &&
+ value->type == AGTV_INTEGER)
+ {
has_end_id = true;
+ }
/* if it gets to this point, it can't be an edge */
else
+ {
return false;
+ }
}
return (has_id && has_label && has_properties &&
has_start_id && has_end_id);
@@ -2917,8 +2949,25 @@ static agtype_value *execute_array_access_operator_internal(agtype *array,
int64 array_index)
{
agtype_value *array_element_value = NULL;
- uint32 size = (array_value == NULL) ? AGT_ROOT_COUNT(array) :
- array_value->val.array.num_elems;
+ uint32 size = 0;
+
+ /* get the size of the array, given the type of the input */
+ if (array_value == NULL)
+ {
+ size = AGT_ROOT_COUNT(array);
+ }
+ else if (array_value->type == AGTV_ARRAY)
+ {
+ size = array_value->val.array.num_elems;
+ }
+ else if (array_value->type == AGTV_BINARY)
+ {
+ size = AGTYPE_CONTAINER_SIZE(array_value->val.binary.data);
+ }
+ else
+ {
+ elog(ERROR, "execute_array_access_operator_internal: unexpected type");
+ }
/* adjust for negative index values */
if (array_index < 0)
@@ -3424,32 +3473,45 @@ Datum agtype_access_slice(PG_FUNCTION_ARGS)
agtype_value *lidx_value = NULL;
agtype_value *uidx_value = NULL;
agtype_in_state result;
- agtype *array;
+ agtype *array = NULL;
int64 upper_index = 0;
int64 lower_index = 0;
- uint32 array_size;
- int64 i;
+ uint32 array_size = 0;
+ int64 i = 0;
/* return null if the array to slice is null */
if (PG_ARGISNULL(0))
+ {
PG_RETURN_NULL();
+ }
+
/* return an error if both indices are NULL */
if (PG_ARGISNULL(1) && PG_ARGISNULL(2))
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("slice start and/or end is required")));
+ }
+
/* 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))
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("slice must access a list")));
+ }
+
+ /* get its size */
array_size = AGT_ROOT_COUNT(array);
+
/* if we don't have a lower bound, make it 0 */
if (PG_ARGISNULL(1))
+ {
lower_index = 0;
+ }
else
{
lidx_value = get_ith_agtype_value_from_container(
- &AG_GET_ARG_AGTYPE_P(1)->root, 0);
+ &(AG_GET_ARG_AGTYPE_P(1))->root, 0);
/* adjust for AGTV_NULL */
if (lidx_value->type == AGTV_NULL)
{
@@ -3457,13 +3519,16 @@ Datum agtype_access_slice(PG_FUNCTION_ARGS)
lidx_value = NULL;
}
}
+
/* if we don't have an upper bound, make it the size of the array */
if (PG_ARGISNULL(2))
+ {
upper_index = array_size;
+ }
else
{
uidx_value = get_ith_agtype_value_from_container(
- &AG_GET_ARG_AGTYPE_P(2)->root, 0);
+ &(AG_GET_ARG_AGTYPE_P(2))->root, 0);
/* adjust for AGTV_NULL */
if (uidx_value->type == AGTV_NULL)
{
@@ -3471,34 +3536,59 @@ Datum agtype_access_slice(PG_FUNCTION_ARGS)
uidx_value = NULL;
}
}
+
/* if both indices are NULL (AGTV_NULL) return an error */
if (lidx_value == NULL && uidx_value == NULL)
+ {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("slice start and/or end is required")));
+ }
+
/* key must be an integer or NULL */
if ((lidx_value != NULL && lidx_value->type != AGTV_INTEGER) ||
(uidx_value != NULL && uidx_value->type != AGTV_INTEGER))
+ {
ereport(ERROR,
(errmsg("array slices must resolve to an integer value")));
+ }
+
/* set indices if not already set */
if (lidx_value)
+ {
lower_index = lidx_value->val.int_value;
+ }
if (uidx_value)
+ {
upper_index = uidx_value->val.int_value;
+ }
+
/* adjust for negative and out of bounds index values */
if (lower_index < 0)
+ {
lower_index = array_size + lower_index;
+ }
if (lower_index < 0)
+ {
lower_index = 0;
+ }
if (lower_index > array_size)
+ {
lower_index = array_size;
+ }
if (upper_index < 0)
+ {
upper_index = array_size + upper_index;
+ }
if (upper_index < 0)
+ {
upper_index = 0;
+ }
if (upper_index > array_size)
+ {
upper_index = array_size;
+ }
+ /* build our result array */
memset(&result, 0, sizeof(agtype_in_state));
result.res = push_agtype_value(&result.parse_state, WAGT_BEGIN_ARRAY,
@@ -3506,9 +3596,10 @@ Datum agtype_access_slice(PG_FUNCTION_ARGS)
/* get array elements */
for (i = lower_index; i < upper_index; i++)
- result.res = push_agtype_value(
- &result.parse_state, WAGT_ELEM,
+ {
+ result.res = push_agtype_value(&result.parse_state, WAGT_ELEM,
get_ith_agtype_value_from_container(&array->root, i));
+ }
result.res = push_agtype_value(&result.parse_state, WAGT_END_ARRAY, NULL);
@@ -6743,7 +6834,9 @@ Datum age_split(PG_FUNCTION_ARGS)
agtv_result = result.res;
}
else
+ {
elog(ERROR, "split() unexpected error");
+ }
PG_RETURN_POINTER(agtype_value_to_agtype(agtv_result));
}