The new version of the patch.

On Friday 27 November 2015 17:23:35 Teodor Sigaev wrote:
> 1
> Documentation isn't very informative
Added example with different results.

> 2
> Seems, error messages are too inconsistent. If you forbid omitting bound in 
> assigment then if all cases error message should be the same or close.
Done.  Skipping lower boundary is no longer an error. 

Thank you for your review.

-- 
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index 4385a09..5a51e07 100644
--- a/doc/src/sgml/array.sgml
+++ b/doc/src/sgml/array.sgml
@@ -257,6 +257,25 @@ SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
 (1 row)
 </programlisting>
 
+  You can skip the <literal><replaceable>lower-bound</replaceable></literal> or <literal><replaceable>upper-bound</replaceable></literal>
+  for get first or last element in slice.
+
+<programlisting>
+SELECT schedule[:][:] FROM sal_emp WHERE name = 'Bill';
+
+        schedule
+------------------------
+ {{meeting,lunch},{training,presentation}}
+(1 row)
+
+SELECT schedule[:2][2:] FROM sal_emp WHERE name = 'Bill';
+
+        schedule
+------------------------
+ {{lunch},{presentation}}
+(1 row)
+</programlisting>
+
   If any dimension is written as a slice, i.e., contains a colon, then all
   dimensions are treated as slices.  Any dimension that has only a single
   number (no colon) is treated as being from 1
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 29f058c..6643714 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -268,10 +268,12 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 	bool		eisnull;
 	ListCell   *l;
 	int			i = 0,
-				j = 0;
+				j = 0,
+				indexexpr;
 	IntArray	upper,
 				lower;
 	int		   *lIndex;
+	AnyArrayType *arrays;
 
 	array_source = ExecEvalExpr(astate->refexpr,
 								econtext,
@@ -293,6 +295,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 	foreach(l, astate->refupperindexpr)
 	{
 		ExprState  *eltstate = (ExprState *) lfirst(l);
+		eisnull = false;
 
 		if (i >= MAXDIM)
 			ereport(ERROR,
@@ -300,10 +303,23 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 					 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
 							i + 1, MAXDIM)));
 
-		upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
-													 econtext,
-													 &eisnull,
-													 NULL));
+		if (eltstate == NULL && astate->refattrlength <= 0)
+		{
+			if (isAssignment)
+				ereport(ERROR,
+					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+					 errmsg("cannot determine upper index for empty array")));
+			arrays = (AnyArrayType *)DatumGetArrayTypeP(array_source);
+			indexexpr = AARR_LBOUND(arrays)[i] + AARR_DIMS(arrays)[i] - 1;
+		}
+		else
+			indexexpr = DatumGetInt32(ExecEvalExpr(eltstate,
+												   econtext,
+												   &eisnull,
+												   NULL));
+
+		upper.indx[i++] = indexexpr;
+
 		/* If any index expr yields NULL, result is NULL or error */
 		if (eisnull)
 		{
@@ -321,6 +337,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 		foreach(l, astate->reflowerindexpr)
 		{
 			ExprState  *eltstate = (ExprState *) lfirst(l);
+			eisnull = false;
 
 			if (j >= MAXDIM)
 				ereport(ERROR,
@@ -328,10 +345,20 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 						 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
 								j + 1, MAXDIM)));
 
-			lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate,
-														 econtext,
-														 &eisnull,
-														 NULL));
+			if (eltstate == NULL)
+			{
+				arrays = (AnyArrayType *)DatumGetArrayTypeP(array_source);
+				indexexpr = AARR_LBOUND(arrays)[j];
+			}
+			else
+				indexexpr = DatumGetInt32(ExecEvalExpr(eltstate,
+													   econtext,
+													   &eisnull,
+													   NULL));
+
+			lower.indx[j++] = indexexpr;
+
+
 			/* If any index expr yields NULL, result is NULL or error */
 			if (eisnull)
 			{
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 26264cb..a761263 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2417,6 +2417,8 @@ _copyAIndices(const A_Indices *from)
 
 	COPY_NODE_FIELD(lidx);
 	COPY_NODE_FIELD(uidx);
+	COPY_SCALAR_FIELD(lidx_default);
+	COPY_SCALAR_FIELD(uidx_default);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index aa6e102..e75b448 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2162,6 +2162,8 @@ _equalAIndices(const A_Indices *a, const A_Indices *b)
 {
 	COMPARE_NODE_FIELD(lidx);
 	COMPARE_NODE_FIELD(uidx);
+	COMPARE_SCALAR_FIELD(lidx_default);
+	COMPARE_SCALAR_FIELD(uidx_default);
 
 	return true;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 012c14b..ed77c75 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2773,6 +2773,8 @@ _outA_Indices(StringInfo str, const A_Indices *node)
 
 	WRITE_NODE_FIELD(lidx);
 	WRITE_NODE_FIELD(uidx);
+	WRITE_BOOL_FIELD(lidx_default);
+	WRITE_BOOL_FIELD(uidx_default);
 }
 
 static void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7916df8..f16456f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -13191,6 +13191,35 @@ indirection_el:
 					A_Indices *ai = makeNode(A_Indices);
 					ai->lidx = NULL;
 					ai->uidx = $2;
+					ai->lidx_default = false;
+					ai->uidx_default = false;
+					$$ = (Node *) ai;
+				}
+			| '[' ':' ']'
+				{
+					A_Indices *ai = makeNode(A_Indices);
+					ai->lidx = NULL;
+					ai->uidx = NULL;
+					ai->lidx_default = true;
+					ai->uidx_default = true;
+					$$ = (Node *) ai;
+				}
+			| '[' ':' a_expr ']'
+				{
+					A_Indices *ai = makeNode(A_Indices);
+					ai->lidx = NULL;
+					ai->uidx = $3;
+					ai->lidx_default = true;
+					ai->uidx_default = false;
+					$$ = (Node *) ai;
+				}
+			| '[' a_expr ':' ']'
+				{
+					A_Indices *ai = makeNode(A_Indices);
+					ai->lidx = $2;
+					ai->uidx = NULL;
+					ai->lidx_default = false;
+					ai->uidx_default = true;
 					$$ = (Node *) ai;
 				}
 			| '[' a_expr ':' a_expr ']'
@@ -13198,6 +13227,8 @@ indirection_el:
 					A_Indices *ai = makeNode(A_Indices);
 					ai->lidx = $2;
 					ai->uidx = $4;
+					ai->lidx_default = false;
+					ai->uidx_default = false;
 					$$ = (Node *) ai;
 				}
 		;
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 4130cbf..bb5347b 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -311,7 +311,7 @@ transformArraySubscripts(ParseState *pstate,
 		elementType = transformArrayType(&arrayType, &arrayTypMod);
 
 	/*
-	 * A list containing only single subscripts refers to a single array
+	 * A list containing only single subscripts (lidx) refers to a single array
 	 * element.  If any of the items are double subscripts (lower:upper), then
 	 * the subscript expression means an array slice operation. In this case,
 	 * we supply a default lower bound of 1 for any items that contain only a
@@ -322,7 +322,7 @@ transformArraySubscripts(ParseState *pstate,
 	{
 		A_Indices  *ai = (A_Indices *) lfirst(idx);
 
-		if (ai->lidx != NULL)
+		if (ai->lidx != NULL || ai->lidx_default)
 		{
 			isSlice = true;
 			break;
@@ -335,7 +335,7 @@ transformArraySubscripts(ParseState *pstate,
 	foreach(idx, indirection)
 	{
 		A_Indices  *ai = (A_Indices *) lfirst(idx);
-		Node	   *subexpr;
+		Node	   *subexpr = NULL;
 
 		Assert(IsA(ai, A_Indices));
 		if (isSlice)
@@ -356,7 +356,7 @@ transformArraySubscripts(ParseState *pstate,
 							 errmsg("array subscript must have type integer"),
 						parser_errposition(pstate, exprLocation(ai->lidx))));
 			}
-			else
+			else if (ai->lidx_default == false)
 			{
 				/* Make a constant 1 */
 				subexpr = (Node *) makeConst(INT4OID,
@@ -369,19 +369,24 @@ transformArraySubscripts(ParseState *pstate,
 			}
 			lowerIndexpr = lappend(lowerIndexpr, subexpr);
 		}
-		subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
-		/* If it's not int4 already, try to coerce */
-		subexpr = coerce_to_target_type(pstate,
-										subexpr, exprType(subexpr),
-										INT4OID, -1,
-										COERCION_ASSIGNMENT,
-										COERCE_IMPLICIT_CAST,
-										-1);
-		if (subexpr == NULL)
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("array subscript must have type integer"),
-					 parser_errposition(pstate, exprLocation(ai->uidx))));
+		if (ai->uidx_default == false)
+		{
+			subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
+			/* If it's not int4 already, try to coerce */
+			subexpr = coerce_to_target_type(pstate,
+											subexpr, exprType(subexpr),
+											INT4OID, -1,
+											COERCION_ASSIGNMENT,
+											COERCE_IMPLICIT_CAST,
+											-1);
+			if (subexpr == NULL)
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("array subscript must have type integer"),
+						 parser_errposition(pstate, exprLocation(ai->uidx))));
+		}
+		else
+			subexpr = NULL;
 		upperIndexpr = lappend(upperIndexpr, subexpr);
 	}
 
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 1b3fcd6..df41f9f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -650,7 +650,7 @@ transformAssignmentIndirection(ParseState *pstate,
 		if (IsA(n, A_Indices))
 		{
 			subscripts = lappend(subscripts, n);
-			if (((A_Indices *) n)->lidx != NULL)
+			if (((A_Indices *) n)->lidx != NULL || ((A_Indices *) n)->lidx_default)
 				isSlice = true;
 		}
 		else if (IsA(n, A_Star))
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9142e94..ac208cc 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -358,6 +358,8 @@ typedef struct A_Indices
 	NodeTag		type;
 	Node	   *lidx;			/* NULL if it's a single subscript */
 	Node	   *uidx;
+	bool		lidx_default;
+	bool		uidx_default;
 } A_Indices;
 
 /*
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 73fb5a2..27fb45c 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2031,3 +2031,34 @@ SELECT width_bucket(5, ARRAY[3, 4, NULL]);
 ERROR:  thresholds array must not contain NULLs
 SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
 ERROR:  thresholds must be one-dimensional array
+-- slices with empty lower and/or upper index
+CREATE TABLE arrtest_s (
+  a       int2[],
+  b       int2[][]
+);
+INSERT INTO arrtest_s VALUES ('{1,2,3,4,5}', '{{1,2,3}, {4,5,6}, {7,8,9}}');
+SELECT a[:3], b[:2][:2] FROM arrtest_s;
+    a    |       b       
+---------+---------------
+ {1,2,3} | {{1,2},{4,5}}
+(1 row)
+
+SELECT a[2:], b[2:][2:] FROM arrtest_s;
+     a     |       b       
+-----------+---------------
+ {2,3,4,5} | {{5,6},{8,9}}
+(1 row)
+
+SELECT a[:], b[:] FROM arrtest_s;
+      a      |             b             
+-------------+---------------------------
+ {1,2,3,4,5} | {{1,2,3},{4,5,6},{7,8,9}}
+(1 row)
+
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+-- errors
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+ERROR:  cannot determine upper index for empty array
+UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
+ERROR:  cannot determine upper index for empty array
+DROP TABLE arrtest_s;
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index b1dd651..4b38197 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -609,3 +609,19 @@ SELECT width_bucket(5, '{}');
 SELECT width_bucket('5'::text, ARRAY[3, 4]::integer[]);
 SELECT width_bucket(5, ARRAY[3, 4, NULL]);
 SELECT width_bucket(5, ARRAY[ARRAY[1, 2], ARRAY[3, 4]]);
+
+-- slices with empty lower and/or upper index
+CREATE TABLE arrtest_s (
+  a       int2[],
+  b       int2[][]
+);
+INSERT INTO arrtest_s VALUES ('{1,2,3,4,5}', '{{1,2,3}, {4,5,6}, {7,8,9}}');
+SELECT a[:3], b[:2][:2] FROM arrtest_s;
+SELECT a[2:], b[2:][2:] FROM arrtest_s;
+SELECT a[:], b[:] FROM arrtest_s;
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+
+-- errors
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
+DROP TABLE arrtest_s;
\ No newline at end of file
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to