Some questions about the array.

Started by YUriy Zhuravlevover 10 years ago56 messages
#1YUriy Zhuravlev
u.zhuravlev@postgrespro.ru

We were some of the issues associated with the behavior of arrays.
1. We would like to implement arrays negative indices (from the end) like in
Python or Ruby: arr[-2] or arr[1: -1]
but as an array can be indexed in the negative area so it probably can not be
done.
2. We would like to add the ability be omitted boundaries in the slice.
Example: arr[2:] or arr[:2]. But there was a problem with the update of an
empty array:
arr[1:][1:] = {1,2,3,4,5,6} can be interpreted as
arr[1:3][1:2] or arr[1:2] [1:3] or [1:1], [1:6]

What is the history of the emergence of such arrays? Maybe something can be
improved?

P.S. I would like List datatype as in Python. Is there any fundamental
objections? Or we just did not have the time and enthusiasm before?
The current implementation I would call vectors or matrices but not arrays.
IMHO

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2Andrew Dunstan
andrew@dunslane.net
In reply to: YUriy Zhuravlev (#1)
Re: Some questions about the array.

On 10/09/2015 08:02 AM, YUriy Zhuravlev wrote:

We were some of the issues associated with the behavior of arrays.
1. We would like to implement arrays negative indices (from the end) like in
Python or Ruby: arr[-2] or arr[1: -1]
but as an array can be indexed in the negative area so it probably can not be
done.
2. We would like to add the ability be omitted boundaries in the slice.
Example: arr[2:] or arr[:2]. But there was a problem with the update of an
empty array:
arr[1:][1:] = {1,2,3,4,5,6} can be interpreted as
arr[1:3][1:2] or arr[1:2] [1:3] or [1:1], [1:6]

What is the history of the emergence of such arrays? Maybe something can be
improved?

P.S. I would like List datatype as in Python. Is there any fundamental
objections? Or we just did not have the time and enthusiasm before?
The current implementation I would call vectors or matrices but not arrays.
IMHO

The name array is now far too baked in to change it.

jsonb and json arrays have many of the characteristics you seem to want.
They are always 0-based and negative indexes count from the end. They
also don't have to be regular, unlike our native arrays.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Andrew Dunstan (#2)
Re: Some questions about the array.

On Fri, Oct 9, 2015 at 6:27 PM, Andrew Dunstan <andrew@dunslane.net> wrote:

On 10/09/2015 08:02 AM, YUriy Zhuravlev wrote:

We were some of the issues associated with the behavior of arrays.
1. We would like to implement arrays negative indices (from the end) like
in
Python or Ruby: arr[-2] or arr[1: -1]
but as an array can be indexed in the negative area so it probably can
not be
done.
2. We would like to add the ability be omitted boundaries in the slice.
Example: arr[2:] or arr[:2]. But there was a problem with the update of an
empty array:
arr[1:][1:] = {1,2,3,4,5,6} can be interpreted as
arr[1:3][1:2] or arr[1:2] [1:3] or [1:1], [1:6]

What is the history of the emergence of such arrays? Maybe something can
be
improved?

P.S. I would like List datatype as in Python. Is there any fundamental
objections? Or we just did not have the time and enthusiasm before?
The current implementation I would call vectors or matrices but not
arrays.
IMHO

The name array is now far too baked in to change it.

jsonb and json arrays have many of the characteristics you seem to want.
They are always 0-based and negative indexes count from the end. They also
don't have to be regular, unlike our native arrays.

jsonb and json arrays support very limited number of types. Casting other
datatypes to/from text is an option, but it is both awkward and not
space-compact.

Omitted boundaries in the slice looks nice for me. Considering problem with
empty array, current behaviour of empty array updating doesn't look
consistent for me.
When updating non-empty array its boundaries isn't extending. If one update
non-empty array out of its boundaries then he get an error "ERROR: array
subscript out of range".
If we extrapolate this logic to empty arrays then we this error should be
thrown on any update of empty array. Despite this, we allow any update of
empty array.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#4Robert Haas
robertmhaas@gmail.com
In reply to: YUriy Zhuravlev (#1)
Re: Some questions about the array.

On Fri, Oct 9, 2015 at 8:02 AM, YUriy Zhuravlev
<u.zhuravlev@postgrespro.ru> wrote:

We were some of the issues associated with the behavior of arrays.
1. We would like to implement arrays negative indices (from the end) like in
Python or Ruby: arr[-2] or arr[1: -1]
but as an array can be indexed in the negative area so it probably can not be
done.

That seems like a complete non-starter because it would break backward
compatibility. Our array implementation allows negative indexes:

rhaas=# select ('[-1:4]={3,1,4,1,5,9}'::int[])[-1];
int4
------
3
(1 row)

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: YUriy Zhuravlev (#1)
1 attachment(s)
Re: Some questions about the array.

Hello again.
I attached simple patch for omitted boundaries in the slice.
This will simplify the writing of SQL. Instead:
select arr[2:array_upper(arr, 1)];
you can write:
select arr[2:];

simple and elegant.
Omitted boundaries is prohibited in UPDATE.

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

extend_slice_v2.patchtext/x-patch; charset=UTF-8; name=extend_slice_v2.patchDownload
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index 4385a09..57614b7 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][1:] FROM sal_emp WHERE name = 'Bill';
+
+        schedule
+------------------------
+ {{meeting,lunch},{training,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 0b4ab23..6d9cad4 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2415,6 +2415,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 df7f6e1..6769740 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2756,6 +2756,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 8bd5119..167e643 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -13198,6 +13198,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 ']'
@@ -13205,6 +13234,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..430f3c1 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -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/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9e1c48d..3d2963b 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..dfcbf19 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2031,3 +2031,35 @@ 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)
+
+-- errors
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+ERROR:  invalid input syntax for integer: "{11, 12, 13}"
+LINE 1: UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{...
+                                     ^
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+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..880b92a 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -609,3 +609,17 @@ 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;
+-- errors
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+DROP TABLE arrtest_s;
\ No newline at end of file
#6YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: YUriy Zhuravlev (#5)
Re: Some questions about the array.

Hello hackers.
There are comments to my patch? Maybe I should create a separate thread?
Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Robert Haas
robertmhaas@gmail.com
In reply to: YUriy Zhuravlev (#6)
Re: Some questions about the array.

On Thu, Nov 5, 2015 at 9:57 AM, YUriy Zhuravlev
<u.zhuravlev@postgrespro.ru> wrote:

Hello hackers.
There are comments to my patch? Maybe I should create a separate thread?
Thanks.

You should add this on commitfest.postgresql.org.

I think the first question that needs to be answered is "do we want
this?". I'm sure I know your answer, but what do other people think?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Craig Ringer
craig@2ndquadrant.com
In reply to: Robert Haas (#7)
Re: Some questions about the array.

On 6 November 2015 at 12:45, Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Nov 5, 2015 at 9:57 AM, YUriy Zhuravlev
<u.zhuravlev@postgrespro.ru> wrote:

Hello hackers.
There are comments to my patch? Maybe I should create a separate thread?
Thanks.

You should add this on commitfest.postgresql.org.

I think the first question that needs to be answered is "do we want
this?". I'm sure I know your answer, but what do other people think?

Omitted bounds are common in other languages and would be handy. I
don't think they'd cause any issues with multi-dimensional arrays or
variable start-pos arrays.

I'd love negative indexes, but the variable-array-start (mis)feature
means we can't have those. I wouldn't shed a tear if
variable-start-position arrays were deprecated and removed, but that's
a multi-year process, and I'm not convinced negative indexes justify
it even though the moveable array start pos feature seems little-used.

Since the start-pos is recorded in the array, I wonder if it's worth
supporting negative indexing for arrays with the default 1-indexed
element numbering, and just ERRORing for others. Does anyone really
use anything else?

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9David G. Johnston
david.g.johnston@gmail.com
In reply to: Craig Ringer (#8)
Re: Some questions about the array.

On Thursday, November 5, 2015, Craig Ringer <craig@2ndquadrant.com> wrote:

On 6 November 2015 at 12:45, Robert Haas <robertmhaas@gmail.com
<javascript:;>> wrote:

On Thu, Nov 5, 2015 at 9:57 AM, YUriy Zhuravlev
<u.zhuravlev@postgrespro.ru <javascript:;>> wrote:

Hello hackers.
There are comments to my patch? Maybe I should create a separate thread?
Thanks.

You should add this on commitfest.postgresql.org.

I think the first question that needs to be answered is "do we want
this?". I'm sure I know your answer, but what do other people think?

Omitted bounds are common in other languages and would be handy. I
don't think they'd cause any issues with multi-dimensional arrays or
variable start-pos arrays.

I'd love negative indexes, but the variable-array-start (mis)feature
means we can't have those. I wouldn't shed a tear if
variable-start-position arrays were deprecated and removed, but that's
a multi-year process, and I'm not convinced negative indexes justify
it even though the moveable array start pos feature seems little-used.

Since the start-pos is recorded in the array, I wonder if it's worth
supporting negative indexing for arrays with the default 1-indexed
element numbering, and just ERRORing for others. Does anyone really
use anything else?

Does it have to be "negative"?

Would something like array[1:~1] as a syntax be acceptable to denote
backward counting?

David J.

#10YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: David G. Johnston (#9)
Re: Some questions about the array.

On Thursday 05 November 2015 22:33:37 you wrote:

Would something like array[1:~1] as a syntax be acceptable to denote
backward counting?

Very interesting idea! I could implement it. I just need to check for side
effects.

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Robert Haas (#7)
Re: Some questions about the array.

On Thursday 05 November 2015 23:45:53 you wrote:

On Thu, Nov 5, 2015 at 9:57 AM, YUriy Zhuravlev

<u.zhuravlev@postgrespro.ru> wrote:

Hello hackers.
There are comments to my patch? Maybe I should create a separate thread?
Thanks.

You should add this on commitfest.postgresql.org.

I created a couple of weeks ago:
https://commitfest.postgresql.org/7/397/

I'm sure I know your answer, but what do other people think?

I wonder the same thing.

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Craig Ringer (#8)
Re: Some questions about the array.

On 11/5/15 10:55 PM, Craig Ringer wrote:

Omitted bounds are common in other languages and would be handy. I
don't think they'd cause any issues with multi-dimensional arrays or
variable start-pos arrays.

+1

I'd love negative indexes, but the variable-array-start (mis)feature
means we can't have those. I wouldn't shed a tear if
variable-start-position arrays were deprecated and removed, but that's
a multi-year process, and I'm not convinced negative indexes justify
it even though the moveable array start pos feature seems little-used.

I'm all for ditching variable start, full stop.

Since the start-pos is recorded in the array, I wonder if it's worth
supporting negative indexing for arrays with the default 1-indexed
element numbering, and just ERRORing for others. Does anyone really
use anything else?

I'd prefer that over using something like ~.
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Robert Haas
robertmhaas@gmail.com
In reply to: Jim Nasby (#12)
Re: Some questions about the array.

On Fri, Nov 6, 2015 at 9:44 PM, Jim Nasby <Jim.Nasby@bluetreble.com> wrote:

Since the start-pos is recorded in the array, I wonder if it's worth
supporting negative indexing for arrays with the default 1-indexed
element numbering, and just ERRORing for others. Does anyone really
use anything else?

I'd prefer that over using something like ~.

I'm not necessarily objecting to that, but it's not impossible that it
could break something for some existing user. We can decide not to
care about that, though.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Robert Haas (#13)
Re: Some questions about the array.

On Sunday 08 November 2015 16:49:20 you wrote:

I'm not necessarily objecting to that, but it's not impossible that it
could break something for some existing user. We can decide not to
care about that, though.

We had an idea. You can use ~ to convert the index to the array which always
starts with 0. Then we can use negative indexes, and you can always find the
beginning of the array.
Example:
we have array [-3:3]={1,2,3,4,5,6,7}
array[~0] == 1
array[~-1] == 7
array[~2:~-2] == {3,4,5,6}

What do you think?
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Pavel Stehule
pavel.stehule@gmail.com
In reply to: YUriy Zhuravlev (#14)
Re: Some questions about the array.

2015-11-09 12:36 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Sunday 08 November 2015 16:49:20 you wrote:

I'm not necessarily objecting to that, but it's not impossible that it
could break something for some existing user. We can decide not to
care about that, though.

We had an idea. You can use ~ to convert the index to the array which
always
starts with 0. Then we can use negative indexes, and you can always find
the
beginning of the array.
Example:
we have array [-3:3]={1,2,3,4,5,6,7}
array[~0] == 1
array[~-1] == 7
array[~2:~-2] == {3,4,5,6}

What do you think?

I am sorry - it is looking pretty obscure. Really need this feature?

Pavel

Show quoted text

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Pavel Stehule (#15)
Re: Some questions about the array.

On Monday 09 November 2015 12:48:54 you wrote:

I am sorry - it is looking pretty obscure. Really need this feature?

IMHO yes.
Now for write: array[~2:~-2] you need like:
array[array_lower(array, 1)+3: array_upper(array, 1)-2]

Worse when long names. Besides the extra functions calls.

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Marc Mamin
M.Mamin@intershop.de
In reply to: Pavel Stehule (#15)
Re: Some questions about the array.

From: pgsql-hackers-owner@postgresql.org [mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Pavel Stehule
Sent: Montag, 9. November 2015 12:49
To: YUriy Zhuravlev
Cc: PostgreSQL Hackers
Subject: Re: [HACKERS] Some questions about the array.

2015-11-09 12:36 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:
On Sunday 08 November 2015 16:49:20 you wrote:

I'm not necessarily objecting to that, but it's not impossible that it
could break something for some existing user. We can decide not to
care about that, though.

We had an idea. You can use ~ to convert the index to the array which always
starts with 0. Then we can use negative indexes, and you can always find the
beginning of the array.
Example:
we have array [-3:3]={1,2,3,4,5,6,7}
array[~0] == 1
array[~-1] == 7
array[~2:~-2] == {3,4,5,6}

What do you think?

Hi,

~ is the bitwise NOT operator.
so array[~n:~m] has a current meaning. Not very useful though.
It would be better to choose another character.

my 2 pence,

Marc Mamin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Pavel Stehule
pavel.stehule@gmail.com
In reply to: YUriy Zhuravlev (#16)
Re: Some questions about the array.

2015-11-09 13:07 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 12:48:54 you wrote:

I am sorry - it is looking pretty obscure. Really need this feature?

IMHO yes.
Now for write: array[~2:~-2] you need like:
array[array_lower(array, 1)+3: array_upper(array, 1)-2]

Worse when long names. Besides the extra functions calls.

It is ugly, but you can wrap it to function - so still I don't see any
reason, why it is necessary

Regards

Pavel

Show quoted text

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Pavel Stehule (#18)
Re: Some questions about the array.

On Monday 09 November 2015 13:29:30 you wrote:

It is ugly, but you can wrap it to function - so still I don't see any
reason, why it is necessary

For example, I'm writing a lot of queries by hands...
This functionality is available in many languages and it's just convenient. Of
course it is possible and without it, but why?

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Vitaly Burovoy
vitaly.burovoy@gmail.com
In reply to: YUriy Zhuravlev (#16)
Re: Some questions about the array.

On 11/9/15, YUriy Zhuravlev <u.zhuravlev@postgrespro.ru> wrote:

On Monday 09 November 2015 12:48:54 you wrote:

I am sorry - it is looking pretty obscure. Really need this feature?

IMHO yes.
Now for write: array[~2:~-2] you need like:
array[array_lower(array, 1)+3: array_upper(array, 1)-2]

Worse when long names. Besides the extra functions calls.

You can write it as a separate function instead of changing current syntax.
Call would be like :
SELECT slice_abs('[-3:3]={1,2,3,4,5,6,7}'::int[], 2, -2) == {3,4,5,6}
SELECT slice_abs('[-3:3]={1,2,3,4,5,6,7}'::int[], 2, NULL) ==
{3,4,5,6,7} -- omitting boundaries
--
Best regards,
Vitaly Burovoy

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Vitaly Burovoy (#20)
Re: Some questions about the array.

On Monday 09 November 2015 04:33:28 you wrote:

You can write it as a separate function instead of changing current syntax.

I do not think, because we have a multi-dimensional arrays.
And why we have [:] syntax now?
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#22Pavel Stehule
pavel.stehule@gmail.com
In reply to: YUriy Zhuravlev (#19)
Re: Some questions about the array.

2015-11-09 13:32 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 13:29:30 you wrote:

It is ugly, but you can wrap it to function - so still I don't see any
reason, why it is necessary

For example, I'm writing a lot of queries by hands...
This functionality is available in many languages and it's just
convenient. Of
course it is possible and without it, but why?

New symbols increase a complexity of our code and our documentation.

If some functionality can be implemented via functions without performance
impacts, we should not to create new operators or syntax - mainly for
corner use cases.

Regards

Pavel

Show quoted text

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Pavel Stehule
pavel.stehule@gmail.com
In reply to: YUriy Zhuravlev (#21)
Re: Some questions about the array.

2015-11-09 13:38 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 04:33:28 you wrote:

You can write it as a separate function instead of changing current

syntax.
I do not think, because we have a multi-dimensional arrays.
And why we have [:] syntax now?

The own implementation of ":" can have a performance impact on code. Now,
it is better on 9.5, but it was impossible to implement it in plpgsql
effectively.

Regards

Pavel

Show quoted text

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#22)
Re: Some questions about the array.

2015-11-09 13:50 GMT+01:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-11-09 13:32 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 13:29:30 you wrote:

It is ugly, but you can wrap it to function - so still I don't see any
reason, why it is necessary

For example, I'm writing a lot of queries by hands...
This functionality is available in many languages and it's just
convenient. Of
course it is possible and without it, but why?

New symbols increase a complexity of our code and our documentation.

If some functionality can be implemented via functions without performance
impacts, we should not to create new operators or syntax - mainly for
corner use cases.

I can understand, so current system of accessing array data has some
disadvantage - the behave was designed twenty years ago, when the arrays
didn't support NULLs, but I am not sure, if introduction secondary
accessing system helps. Probably not.

Regards

Pavel

Show quoted text

Regards

Pavel

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Pavel Stehule (#22)
Re: Some questions about the array.

On Monday 09 November 2015 13:50:20 Pavel Stehule wrote:

New symbols increase a complexity of our code and our documentation.

If some functionality can be implemented via functions without performance
impacts, we should not to create new operators or syntax - mainly for
corner use cases.

Regards

Pavel

Ok we can use {:} instead [:] for zero array access.
The function is the solution half.

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#26Pavel Stehule
pavel.stehule@gmail.com
In reply to: YUriy Zhuravlev (#25)
Re: Some questions about the array.

2015-11-09 14:44 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 13:50:20 Pavel Stehule wrote:

New symbols increase a complexity of our code and our documentation.

If some functionality can be implemented via functions without

performance

impacts, we should not to create new operators or syntax - mainly for
corner use cases.

Regards

Pavel

Ok we can use {:} instead [:] for zero array access.
The function is the solution half.

It isn't solution. The any syntax/behave change have to have stronger
motivation. We had so talk about it 20 years ago :(

Regards

Pavel

Show quoted text

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Pavel Stehule (#26)
Re: Some questions about the array.

On Mon, Nov 9, 2015 at 4:53 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-11-09 14:44 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 13:50:20 Pavel Stehule wrote:

New symbols increase a complexity of our code and our documentation.

If some functionality can be implemented via functions without

performance

impacts, we should not to create new operators or syntax - mainly for
corner use cases.

Regards

Pavel

Ok we can use {:} instead [:] for zero array access.
The function is the solution half.

It isn't solution. The any syntax/behave change have to have stronger
motivation. We had so talk about it 20 years ago :(

Assuming array[~n] has a current meaning, could we give a try to new syntax
which doesn't have current meaning? Not yet sure what exactly it could be...

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#28Pavel Stehule
pavel.stehule@gmail.com
In reply to: Alexander Korotkov (#27)
Re: Some questions about the array.

2015-11-09 17:55 GMT+01:00 Alexander Korotkov <a.korotkov@postgrespro.ru>:

On Mon, Nov 9, 2015 at 4:53 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-11-09 14:44 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 13:50:20 Pavel Stehule wrote:

New symbols increase a complexity of our code and our documentation.

If some functionality can be implemented via functions without

performance

impacts, we should not to create new operators or syntax - mainly for
corner use cases.

Regards

Pavel

Ok we can use {:} instead [:] for zero array access.
The function is the solution half.

It isn't solution. The any syntax/behave change have to have stronger
motivation. We had so talk about it 20 years ago :(

Assuming array[~n] has a current meaning, could we give a try to new
syntax which doesn't have current meaning? Not yet sure what exactly it
could be...

Using this syntax can introduce compatibility issues -
http://www.postgresql.org/docs/9.1/static/sql-createoperator.html

Regards

Pavel

Show quoted text

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#29YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Craig Ringer (#8)
Re: Some questions about the array.

On Friday 06 November 2015 12:55:44 you wrote:

Omitted bounds are common in other languages and would be handy. I
don't think they'd cause any issues with multi-dimensional arrays or
variable start-pos arrays.

And yet, what about my patch?
Discussions about ~ and{:} it seems optional.

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Pavel Stehule (#28)
Re: Some questions about the array.

On Mon, Nov 9, 2015 at 8:23 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-11-09 17:55 GMT+01:00 Alexander Korotkov <a.korotkov@postgrespro.ru>:

On Mon, Nov 9, 2015 at 4:53 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-11-09 14:44 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Monday 09 November 2015 13:50:20 Pavel Stehule wrote:

New symbols increase a complexity of our code and our documentation.

If some functionality can be implemented via functions without

performance

impacts, we should not to create new operators or syntax - mainly for
corner use cases.

Regards

Pavel

Ok we can use {:} instead [:] for zero array access.
The function is the solution half.

It isn't solution. The any syntax/behave change have to have stronger
motivation. We had so talk about it 20 years ago :(

Assuming array[~n] has a current meaning, could we give a try to new
syntax which doesn't have current meaning? Not yet sure what exactly it
could be...

Using this syntax can introduce compatibility issues -
http://www.postgresql.org/docs/9.1/static/sql-createoperator.html

I actually meant some other syntax which doesn't introduce compatibility
issues. For instance, array{n} doesn't have meaning in current syntax
AFAICS.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#31Pavel Stehule
pavel.stehule@gmail.com
In reply to: YUriy Zhuravlev (#29)
Re: Some questions about the array.

2015-11-11 12:25 GMT+01:00 YUriy Zhuravlev <u.zhuravlev@postgrespro.ru>:

On Friday 06 November 2015 12:55:44 you wrote:

Omitted bounds are common in other languages and would be handy. I
don't think they'd cause any issues with multi-dimensional arrays or
variable start-pos arrays.

And yet, what about my patch?
Discussions about ~ and{:} it seems optional.

In this case the syntax is major issue. Any language should not to have any
possible feature on the world.

My opinion on this proposal is same - the general benefit for users is
minimal and disputable - Introduction new syntax is wrong idea.

So -1

Pavel

Show quoted text

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#32YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Pavel Stehule (#31)
Re: Some questions about the array.

On Wednesday 11 November 2015 17:29:31 you wrote:

In this case the syntax is major issue. Any language should not to have any
possible feature on the world.

I am about omitted boundaries. It almost does not change the syntax and with
nothing conflicts.

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#33Teodor Sigaev
teodor@sigaev.ru
In reply to: YUriy Zhuravlev (#29)
Re: Some questions about the array.

YUriy Zhuravlev wrote:

On Friday 06 November 2015 12:55:44 you wrote:

Omitted bounds are common in other languages and would be handy. I
don't think they'd cause any issues with multi-dimensional arrays or
variable start-pos arrays.

And yet, what about my patch?

My vote: let us do it, mean, omitting bounds. It simplifies syntax in rather
popular queries.

Discussions about ~ and{:} it seems optional.

~ is allowed as unary operator and therefore such syntax will introduce
incompatibily/ambiguity.

--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#34Teodor Sigaev
teodor@sigaev.ru
In reply to: YUriy Zhuravlev (#5)
Re: Some questions about the array.

Some comments about patch
1
Documentation isn't very informative
Outputs of
SELECT schedule[:][:] FROM sal_emp WHERE name = 'Bill'
and
SELECT schedule[:2][1:] FROM sal_emp WHERE name = 'Bill';
are the same. Suppose, it's better to have differs ones.

2
# create table xxx (a int[]);
# update xxx set a[2:] = '{1,2}';
UPDATE 0
# update xxx set a[2:] = '{1,2}';
ERROR: cannot determine upper index for empty array
# update xxx set a[:2] = '{1,2}';
ERROR: invalid input syntax for integer: "{1,2}"
# update xxx set a[:] = '{1,2}';
ERROR: invalid input syntax for integer: "{1,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.

YUriy Zhuravlev wrote:

Hello again.
I attached simple patch for omitted boundaries in the slice.
This will simplify the writing of SQL. Instead:
select arr[2:array_upper(arr, 1)];
you can write:
select arr[2:];

simple and elegant.
Omitted boundaries is prohibited in UPDATE.

Thanks.

--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#35YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Teodor Sigaev (#34)
1 attachment(s)
Re: Some questions about the array.

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

Attachments:

extend_slice_v3.patchtext/x-patch; charset=UTF-8; name=extend_slice_v3.patchDownload
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
#36Merlin Moncure
mmoncure@gmail.com
In reply to: Teodor Sigaev (#33)
Re: Some questions about the array.

On Thu, Nov 26, 2015 at 6:08 AM, Teodor Sigaev <teodor@sigaev.ru> wrote:

YUriy Zhuravlev wrote:

On Friday 06 November 2015 12:55:44 you wrote:

Omitted bounds are common in other languages and would be handy. I
don't think they'd cause any issues with multi-dimensional arrays or
variable start-pos arrays.

And yet, what about my patch?

My vote: let us do it, mean, omitting bounds. It simplifies syntax in rather
popular queries.

+1 useful and intuitive

Discussions about ~ and{:} it seems optional.

~ is allowed as unary operator and therefore such syntax will introduce
incompatibily/ambiguity.

+1 IMO this line of thinking is a dead end. Better handled via
functions, not syntax

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#37YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Merlin Moncure (#36)
Re: Some questions about the array.

On Monday 30 November 2015 08:58:49 you wrote:

+1 IMO this line of thinking is a dead end. Better handled via
functions, not syntax

Maybe then add array_pyslice(start, end) when start is 0 and with negative
indexes? Only for 1D array.
What do you think?

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#38Teodor Sigaev
teodor@sigaev.ru
In reply to: YUriy Zhuravlev (#35)
Re: Some questions about the array.

On Friday 27 November 2015 17:23:35 Teodor Sigaev wrote:

1
Documentation isn't very informative

Added example with different results.

Perfect

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.

Much better, but:

# create table xxx (a int[]);
# update xxx set a[2:] = '{1,2}';
UPDATE 0
# insert into xxx values ('{1,2,3,3,4,4,5}');
INSERT 0 1
# update xxx set a[2:] = '{1,2}';
ERROR: cannot determine upper index for empty array

As I understand, update should fail with any array, so, first update should fail
too. Am I right?

--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#39YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Teodor Sigaev (#38)
1 attachment(s)
Re: Some questions about the array.

On Tuesday 01 December 2015 15:30:47 Teodor Sigaev wrote:

As I understand, update should fail with any array, so, first update should
fail too. Am I right?

You right. Done. New patch in attach.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

extend_slice_v4.patchtext/x-patch; charset=UTF-8; name=extend_slice_v4.patchDownload
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index 4385a09..6ee71a5 100644
--- a/doc/src/sgml/array.sgml
+++ b/doc/src/sgml/array.sgml
@@ -257,6 +257,26 @@ SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
 (1 row)
 </programlisting>
 
+  Possible to 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..aa64ca7 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 (uidx) 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,9 +335,14 @@ transformArraySubscripts(ParseState *pstate,
 	foreach(idx, indirection)
 	{
 		A_Indices  *ai = (A_Indices *) lfirst(idx);
-		Node	   *subexpr;
+		Node	   *subexpr = NULL;
 
 		Assert(IsA(ai, A_Indices));
+		if (ai->uidx == NULL && assignFrom != NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+					 errmsg("cannot determine upper index for empty array")));
+
 		if (isSlice)
 		{
 			if (ai->lidx)
@@ -356,7 +361,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 +374,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
#40Merlin Moncure
mmoncure@gmail.com
In reply to: YUriy Zhuravlev (#37)
Re: Some questions about the array.

On Mon, Nov 30, 2015 at 3:05 PM, YUriy Zhuravlev
<u.zhuravlev@postgrespro.ru> wrote:

On Monday 30 November 2015 08:58:49 you wrote:

+1 IMO this line of thinking is a dead end. Better handled via
functions, not syntax

Maybe then add array_pyslice(start, end) when start is 0 and with negative
indexes? Only for 1D array.
What do you think?

TBH, I'm not really thrilled about the concept in general; it (zero
based indexing support) doesn't meet the standard of necessity for
adding to the core API and as stated it's much to magical. If it was
me, I'd be making a pgxn extension for zero based arrays that are zero
based; it could be 100% SQL wrappers so I'd be pretty easy to install
for interested parties.

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#41YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: YUriy Zhuravlev (#39)
1 attachment(s)
Re: Some questions about the array.

On Tuesday 01 December 2015 15:43:47 you wrote:

On Tuesday 01 December 2015 15:30:47 Teodor Sigaev wrote:

As I understand, update should fail with any array, so, first update
should
fail too. Am I right?

You right. Done. New patch in attach.

Found error when omitted lower bound in INSERT like this:
INSERT INTO arrtest_s (a[:2], b[1:2]) VALUES ('{1,2,3,4,5}', '{7,8,9}');

I fix it in new patch. Lower bound for new array is 1 by default.

Thanks.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

extend_slice_v5.patchtext/x-patch; charset=UTF-8; name=extend_slice_v5.patchDownload
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index 4385a09..6ee71a5 100644
--- a/doc/src/sgml/array.sgml
+++ b/doc/src/sgml/array.sgml
@@ -257,6 +257,26 @@ SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
 (1 row)
 </programlisting>
 
+  Possible to 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..f300b31 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,25 @@ 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)
+			{
+				if (*isNull)
+					indexexpr = 1;
+				else
+				{
+					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..aa64ca7 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 (uidx) 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,9 +335,14 @@ transformArraySubscripts(ParseState *pstate,
 	foreach(idx, indirection)
 	{
 		A_Indices  *ai = (A_Indices *) lfirst(idx);
-		Node	   *subexpr;
+		Node	   *subexpr = NULL;
 
 		Assert(IsA(ai, A_Indices));
+		if (ai->uidx == NULL && assignFrom != NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+					 errmsg("cannot determine upper index for empty array")));
+
 		if (isSlice)
 		{
 			if (ai->lidx)
@@ -356,7 +361,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 +374,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
#42YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Merlin Moncure (#40)
Re: Some questions about the array.

On Tuesday 01 December 2015 08:38:21 you wrote:

it (zero
based indexing support) doesn't meet the standard of necessity for
adding to the core API and as stated it's much to magical.

We do not touch the arrays, we simply create a function to access them with a
comfortable behavior. Creating a separate array types in the form extension is
very difficult IMHO.

--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#43Merlin Moncure
mmoncure@gmail.com
In reply to: YUriy Zhuravlev (#42)
Re: Some questions about the array.

On Tue, Dec 1, 2015 at 8:46 AM, YUriy Zhuravlev
<u.zhuravlev@postgrespro.ru> wrote:

On Tuesday 01 December 2015 08:38:21 you wrote:

it (zero
based indexing support) doesn't meet the standard of necessity for
adding to the core API and as stated it's much to magical.

We do not touch the arrays, we simply create a function to access them with a
comfortable behavior. Creating a separate array types in the form extension is
very difficult IMHO.

Correct; what I'm saying is that we don't need core API support for
zero based array indexing. A hypothetical extension could give 100%
function based support for that so that equivalents to all functions
are given: array_upper, array_lower, etc etc etc. You are correct
that it could not implement alternative syntactical array features.

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#44Teodor Sigaev
teodor@sigaev.ru
In reply to: YUriy Zhuravlev (#41)
Re: Some questions about the array.

Some inconsistency (if we believe that omitted lower bound is equal to 1):
regression=# insert into arrtest_s values
('[-1:9]={3,1,4,1,5,9,5,6,7,8,9}'::int[], null);
INSERT 0 1
regression=# UPDATE arrtest_s SET a[:2] = '{23, 24, 25}';
ERROR: source array too small
regression=# UPDATE arrtest_s SET a[1:2] = '{23, 24, 25}';
UPDATE 1

Seems, omitting boundaries in insert/update isn't a good idea. I suggest to
allow omitting only in select subscripting.

YUriy Zhuravlev wrote:

On Tuesday 01 December 2015 15:43:47 you wrote:

On Tuesday 01 December 2015 15:30:47 Teodor Sigaev wrote:

As I understand, update should fail with any array, so, first update
should
fail too. Am I right?

You right. Done. New patch in attach.

Found error when omitted lower bound in INSERT like this:
INSERT INTO arrtest_s (a[:2], b[1:2]) VALUES ('{1,2,3,4,5}', '{7,8,9}');

I fix it in new patch. Lower bound for new array is 1 by default.

Thanks.

--
Teodor Sigaev E-mail: teodor@sigaev.ru
WWW: http://www.sigaev.ru/

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#45YUriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Teodor Sigaev (#44)
1 attachment(s)
Re: Some questions about the array.

On Friday 04 December 2015 16:52:48 Teodor Sigaev wrote:

Seems, omitting boundaries in insert/update isn't a good idea. I suggest to
allow omitting only in select subscripting.

It was my last attempt to do so. So now I agree, the most simple is now
disabled for insert and update. New patch in attach.
--
YUriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

extend_slice_v6.patchtext/x-patch; charset=UTF-8; name=extend_slice_v6.patchDownload
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index 4385a09..6ee71a5 100644
--- a/doc/src/sgml/array.sgml
+++ b/doc/src/sgml/array.sgml
@@ -257,6 +257,26 @@ SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
 (1 row)
 </programlisting>
 
+  Possible to 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..d9bf977 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,19 @@ 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..55c7d32 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 (uidx) 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,9 +335,15 @@ transformArraySubscripts(ParseState *pstate,
 	foreach(idx, indirection)
 	{
 		A_Indices  *ai = (A_Indices *) lfirst(idx);
-		Node	   *subexpr;
+		Node	   *subexpr = NULL;
 
 		Assert(IsA(ai, A_Indices));
+		if ((ai->uidx_default || ai->lidx_default) && assignFrom != NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+					 errmsg("you can't omitted the upper or lower"
+							" boundaries when updating or inserting")));
+
 		if (isSlice)
 		{
 			if (ai->lidx)
@@ -356,7 +362,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 +375,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..46cdd6b 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)
+
+-- errors
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+ERROR:  you can't omitted the upper or lower boundaries when updating or inserting
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+ERROR:  you can't omitted the upper or lower boundaries when updating or inserting
+UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
+ERROR:  you can't omitted the upper or lower boundaries when updating or inserting
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index b1dd651..6a357a9 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -609,3 +609,18 @@ 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;
+
+-- errors
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
\ No newline at end of file
#46Robert Haas
robertmhaas@gmail.com
In reply to: Merlin Moncure (#43)
Re: Some questions about the array.

On Wed, Dec 2, 2015 at 3:01 PM, Merlin Moncure <mmoncure@gmail.com> wrote:

On Tue, Dec 1, 2015 at 8:46 AM, YUriy Zhuravlev
<u.zhuravlev@postgrespro.ru> wrote:

On Tuesday 01 December 2015 08:38:21 you wrote:

it (zero
based indexing support) doesn't meet the standard of necessity for
adding to the core API and as stated it's much to magical.

We do not touch the arrays, we simply create a function to access them with a
comfortable behavior. Creating a separate array types in the form extension is
very difficult IMHO.

Correct; what I'm saying is that we don't need core API support for
zero based array indexing.

Yes. I think adding new functions that use an indexing convention
inconsistent with the one we're using for everything else ought to be
completely out of the question.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#47Uriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: YUriy Zhuravlev (#45)
Re: Some questions about the array.

In the continuation of thread:
/messages/by-id/19144.1450457693@sss.pgh.pa.us

I'm dubious that the parsetree representation is well-chosen.
Probably a single is_slice flag would have been better.

What do you mean? This flag is for what? You are about the A_Indices
node(lidx_default/uidx_default)?

All the other issues I fixed.

Thanks!

--
Uriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#48Tom Lane
tgl@sss.pgh.pa.us
In reply to: Uriy Zhuravlev (#47)
Re: Some questions about the array.

Uriy Zhuravlev <u.zhuravlev@postgrespro.ru> writes:

I'm dubious that the parsetree representation is well-chosen.
Probably a single is_slice flag would have been better.

What do you mean? This flag is for what? You are about the A_Indices
node(lidx_default/uidx_default)?

Yes. Those flags are partially redundant with the subtree pointers being
NULL, and there are combinations that would be invalid (such as
lidx_default being set but lidx not being null), and it's pretty unobvious
what the difference in representation is between a non-slice case and a
slice case with only the upper index provided. In fact, since you have
five syntaxes to represent, it's impossible for the two bools to
distinguish them all, which means that at least one case *must* be
identified by null-ness of a pointer contradicting what the corresponding
bool's setting would imply. So this just seems like a mess to me.

I think it would come out cleaner if you had just one bool is_slice,
which corresponds directly to whether a colon was present. The four
sub-possibilities of colon notation would be represented by combinations
of null and non-null lidx and uidx. With is_slice false, the only valid
case is lidx==NULL, uidx!=NULL, as before for non-slice notation.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#49Michael Paquier
michael.paquier@gmail.com
In reply to: Tom Lane (#48)
Re: Some questions about the array.

On Tue, Dec 22, 2015 at 2:28 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Uriy Zhuravlev <u.zhuravlev@postgrespro.ru> writes:

I'm dubious that the parsetree representation is well-chosen.
Probably a single is_slice flag would have been better.

What do you mean? This flag is for what? You are about the A_Indices
node(lidx_default/uidx_default)?

Yes. Those flags are partially redundant with the subtree pointers being
NULL, and there are combinations that would be invalid (such as
lidx_default being set but lidx not being null), and it's pretty unobvious
what the difference in representation is between a non-slice case and a
slice case with only the upper index provided. In fact, since you have
five syntaxes to represent, it's impossible for the two bools to
distinguish them all, which means that at least one case *must* be
identified by null-ness of a pointer contradicting what the corresponding
bool's setting would imply. So this just seems like a mess to me.

I think it would come out cleaner if you had just one bool is_slice,
which corresponds directly to whether a colon was present. The four
sub-possibilities of colon notation would be represented by combinations
of null and non-null lidx and uidx. With is_slice false, the only valid
case is lidx==NULL, uidx!=NULL, as before for non-slice notation.

Patch is still in the works and author is still active, so moved to next CF.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#50Uriy Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Tom Lane (#48)
Re: Some questions about the array.

On понедельник, 21 декабря 2015 г. 20:28:43 MSK, Tom Lane wrote:

With is_slice false, the only valid
case is lidx==NULL, uidx!=NULL, as before for non-slice notation.

But now it becomes valid syntax:
select ('{1,2,3,4}'::int[])[NULL:NULL];
I do not think it's logical. Especially if in [:] function is used.
Unexpected behavior.

Thanks.
--
Uriy Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#51Tom Lane
tgl@sss.pgh.pa.us
In reply to: Uriy Zhuravlev (#50)
Re: Some questions about the array.

Uriy Zhuravlev <u.zhuravlev@postgrespro.ru> writes:

On понедельник, 21 декабря 2015 г. 20:28:43 MSK, Tom Lane wrote:

With is_slice false, the only valid
case is lidx==NULL, uidx!=NULL, as before for non-slice notation.

But now it becomes valid syntax:
select ('{1,2,3,4}'::int[])[NULL:NULL];
I do not think it's logical. Especially if in [:] function is used.
Unexpected behavior.

I think you are confused about the difference between a NULL constant
(which would give rise to an A_Const syntax tree node) and a NULL
syntax tree pointer (which cannot arise from any actual syntactical
construct, and would only be present if the grammar put it there due
to lack of any corresponding item in the input).

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#52Yury Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Tom Lane (#51)
Re: Some questions about the array.

I think you are confused about the difference between a NULL constant
(which would give rise to an A_Const syntax tree node) and a NULL
syntax tree pointer (which cannot arise from any actual syntactical
construct, and would only be present if the grammar put it there due
to lack of any corresponding item in the input).

regards, tom lane

You're right. I will try to provide a patch as soon as possible.
Thanks.

--
Yury Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#53Yury Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Tom Lane (#51)
1 attachment(s)
Re: Some questions about the array.

New patch version in attachment.
Thanks.

--
Yury Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

extend_slice_v7.patchtext/x-patchDownload
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml
index 4385a09..305cabb 100644
--- a/doc/src/sgml/array.sgml
+++ b/doc/src/sgml/array.sgml
@@ -257,6 +257,26 @@ SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';
 (1 row)
 </programlisting>
 
+  It is possible to omit <literal><replaceable>lower-bound</replaceable></literal> or
+  <literal><replaceable>upper-bound</replaceable></literal>
+  of slice operator, since the missing bound will default to the index of the corresponding item.
+
+<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..f586d57 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,29 @@ 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)
+		{
+			if (isAssignment)
+				ereport(ERROR,
+					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+					 errmsg("cannot determine upper index for empty array")));
+
+			if (astate->refattrlength > 0)
+				ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("slices of fixed-length arrays not implemented")));
+
+			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 +343,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 		foreach(l, astate->reflowerindexpr)
 		{
 			ExprState  *eltstate = (ExprState *) lfirst(l);
+			eisnull = false;
 
 			if (j >= MAXDIM)
 				ereport(ERROR,
@@ -328,10 +351,19 @@ 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..fe848d5 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2417,6 +2417,7 @@ _copyAIndices(const A_Indices *from)
 
 	COPY_NODE_FIELD(lidx);
 	COPY_NODE_FIELD(uidx);
+	COPY_SCALAR_FIELD(is_slice);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index aa6e102..00f98ef 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2162,6 +2162,7 @@ _equalAIndices(const A_Indices *a, const A_Indices *b)
 {
 	COMPARE_NODE_FIELD(lidx);
 	COMPARE_NODE_FIELD(uidx);
+	COMPARE_SCALAR_FIELD(is_slice);
 
 	return true;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 012c14b..5c6326d 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2773,6 +2773,7 @@ _outA_Indices(StringInfo str, const A_Indices *node)
 
 	WRITE_NODE_FIELD(lidx);
 	WRITE_NODE_FIELD(uidx);
+	WRITE_BOOL_FIELD(is_slice);
 }
 
 static void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7916df8..4afc572 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -13191,6 +13191,31 @@ indirection_el:
 					A_Indices *ai = makeNode(A_Indices);
 					ai->lidx = NULL;
 					ai->uidx = $2;
+					ai->is_slice = false;
+					$$ = (Node *) ai;
+				}
+			| '[' ':' ']'
+				{
+					A_Indices *ai = makeNode(A_Indices);
+					ai->lidx = NULL;
+					ai->uidx = NULL;
+					ai->is_slice = true;
+					$$ = (Node *) ai;
+				}
+			| '[' ':' a_expr ']'
+				{
+					A_Indices *ai = makeNode(A_Indices);
+					ai->lidx = NULL;
+					ai->uidx = $3;
+					ai->is_slice = true;
+					$$ = (Node *) ai;
+				}
+			| '[' a_expr ':' ']'
+				{
+					A_Indices *ai = makeNode(A_Indices);
+					ai->lidx = $2;
+					ai->uidx = NULL;
+					ai->is_slice = true;
 					$$ = (Node *) ai;
 				}
 			| '[' a_expr ':' a_expr ']'
@@ -13198,6 +13223,7 @@ indirection_el:
 					A_Indices *ai = makeNode(A_Indices);
 					ai->lidx = $2;
 					ai->uidx = $4;
+					ai->is_slice = true;
 					$$ = (Node *) ai;
 				}
 		;
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 4130cbf..b02bdc2 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 (uidx) 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->is_slice)
 		{
 			isSlice = true;
 			break;
@@ -335,9 +335,19 @@ transformArraySubscripts(ParseState *pstate,
 	foreach(idx, indirection)
 	{
 		A_Indices  *ai = (A_Indices *) lfirst(idx);
-		Node	   *subexpr;
+		Node	   *subexpr = NULL;
 
 		Assert(IsA(ai, A_Indices));
+		if (ai->is_slice
+			&& (ai->lidx == NULL || ai->uidx == NULL)
+			&& assignFrom != NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+					 errmsg("array subscript must have both boundaries"),
+					 errhint("You can't omit the upper or lower"
+							 " boundaries when updating or inserting"),
+					 parser_errposition(pstate, exprLocation(arrayBase))));
+
 		if (isSlice)
 		{
 			if (ai->lidx)
@@ -354,34 +364,30 @@ transformArraySubscripts(ParseState *pstate,
 					ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
 							 errmsg("array subscript must have type integer"),
-						parser_errposition(pstate, exprLocation(ai->lidx))));
+							 parser_errposition(pstate, exprLocation(ai->lidx))));
 			}
 			else
-			{
-				/* Make a constant 1 */
-				subexpr = (Node *) makeConst(INT4OID,
-											 -1,
-											 InvalidOid,
-											 sizeof(int32),
-											 Int32GetDatum(1),
-											 false,
-											 true);		/* pass by value */
-			}
+				subexpr = NULL;
 			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->is_slice && ai->uidx == NULL)
+			subexpr = NULL;
+		else
+		{
+			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))));
+		}
 		upperIndexpr = lappend(upperIndexpr, subexpr);
 	}
 
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 1b3fcd6..8c2c38d 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)->is_slice)
 				isSlice = true;
 		}
 		else if (IsA(n, A_Star))
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9142e94..a8c12bc 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -357,7 +357,8 @@ typedef struct A_Indices
 {
 	NodeTag		type;
 	Node	   *lidx;			/* NULL if it's a single subscript */
-	Node	   *uidx;
+	Node	   *uidx;			/* upper bound */
+	bool		is_slice;		/* true if slice bounds */
 } A_Indices;
 
 /*
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 73fb5a2..3084fe0 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2031,3 +2031,59 @@ 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)
+
+-- errors
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+ERROR:  array subscript must have both boundaries
+LINE 1: UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{...
+                             ^
+HINT:  You can't omit the upper or lower boundaries when updating or inserting
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+ERROR:  array subscript must have both boundaries
+LINE 1: UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{...
+                             ^
+HINT:  You can't omit the upper or lower boundaries when updating or inserting
+UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
+ERROR:  array subscript must have both boundaries
+LINE 1: UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
+                             ^
+HINT:  You can't omit the upper or lower boundaries when updating or inserting
+-- access to fixed-lenght arrays
+CREATE TEMP TABLE POINT_TBL(f1 point);
+INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
+SELECT f1[0] FROM POINT_TBL;
+ f1 
+----
+  0
+(1 row)
+
+-- errors
+SELECT f1[0:1] FROM POINT_TBL;
+ERROR:  slices of fixed-length arrays not implemented
+SELECT f1[0:] FROM POINT_TBL;
+ERROR:  slices of fixed-length arrays not implemented
+SELECT f1[:1] FROM POINT_TBL;
+ERROR:  slices of fixed-length arrays not implemented
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index 5f263f9..155972b 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -586,6 +586,7 @@ SELECT user_relns() AS user_relns
  array_index_op_test
  array_op_test
  arrtest
+ arrtest_s
  b
  b_star
  bb
@@ -710,7 +711,7 @@ SELECT user_relns() AS user_relns
  tvvmv
  varchar_tbl
  xacttest
-(132 rows)
+(133 rows)
 
 SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
  name 
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index b1dd651..b5fa7a3 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -609,3 +609,28 @@ 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;
+
+-- errors
+UPDATE arrtest_s SET a[:3] = '{11, 12, 13}', b[:2][:2] = '{{11,12}, {14, 15}}';
+UPDATE arrtest_s SET a[3:] = '{23, 24, 25}', b[2:][2:] = '{{25,26}, {28, 29}}';
+UPDATE arrtest_s SET a[:] = '{23, 24, 25}';
+
+-- access to fixed-lenght arrays
+CREATE TEMP TABLE POINT_TBL(f1 point);
+INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
+SELECT f1[0] FROM POINT_TBL;
+
+-- errors
+SELECT f1[0:1] FROM POINT_TBL;
+SELECT f1[0:] FROM POINT_TBL;
+SELECT f1[:1] FROM POINT_TBL;
#54Tom Lane
tgl@sss.pgh.pa.us
In reply to: Yury Zhuravlev (#53)
Re: Some questions about the array.

Yury Zhuravlev <u.zhuravlev@postgrespro.ru> writes:

New patch version in attachment.

It's still awfully short on comments, but I'll see what I can do with it.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#55Tom Lane
tgl@sss.pgh.pa.us
In reply to: Yury Zhuravlev (#53)
Re: Some questions about the array.

Yury Zhuravlev <u.zhuravlev@postgrespro.ru> writes:

New patch version in attachment.

I've committed this with a number of revisions, mostly but not entirely
cosmetic. Worthy of note:

* I did not like the way you were inserting the replacement subscript
values:

+			arrays = (AnyArrayType *)DatumGetArrayTypeP(array_source);
+			indexexpr = AARR_LBOUND(arrays)[i] + AARR_DIMS(arrays)[i] - 1;

If the source array is toasted, this causes an extra detoast operation
for *each* omitted subscript. That could be pretty high overhead for
a large array. The best way to avoid that is to postpone the actual
substitution of the replacement subscript values into array_get_slice
and array_set_slice; which complicates their APIs a bit more, but those
were pretty long argument lists already.

* Having done that, there was no very good reason for the blanket
prohibition on using omitted subscripts in the slice-set case. We only
really need to fail if we're constructing the array from scratch, when
we don't have any existing subscript limits to substitute.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#56Yury Zhuravlev
u.zhuravlev@postgrespro.ru
In reply to: Tom Lane (#55)
Re: Some questions about the array.

I've committed this with a number of revisions, mostly but not entirely
cosmetic.

Thanks Tom!
I feel I still have a lot to learn Postgres to choose the right solution.
Your comments are very valuable.

--
Yury Zhuravlev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers