Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6efbded

Browse files
committed
Allow omitting one or both boundaries in an array slice specifier.
Omitted boundaries represent the upper or lower limit of the correspondingarray subscript. This allows simpler specification of many commonuse-cases.(Revised version of commit9246af6)YUriy Zhuravlev
1 parent0ba3f3b commit6efbded

File tree

15 files changed

+302
-33
lines changed

15 files changed

+302
-33
lines changed

‎doc/src/sgml/array.sgml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,29 @@ SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Bill';
276276
for all dimensions, e.g., <literal>[1:2][1:1]</>, not <literal>[2][1:1]</>.
277277
</para>
278278

279+
<para>
280+
It is possible to omit the <replaceable>lower-bound</replaceable> and/or
281+
<replaceable>upper-bound</replaceable> of a slice specifier; the missing
282+
bound is replaced by the lower or upper limit of the array's subscripts.
283+
For example:
284+
285+
<programlisting>
286+
SELECT schedule[:2][2:] FROM sal_emp WHERE name = 'Bill';
287+
288+
schedule
289+
------------------------
290+
{{lunch},{presentation}}
291+
(1 row)
292+
293+
SELECT schedule[:][1:1] FROM sal_emp WHERE name = 'Bill';
294+
295+
schedule
296+
------------------------
297+
{{meeting},{training}}
298+
(1 row)
299+
</programlisting>
300+
</para>
301+
279302
<para>
280303
An array subscript expression will return null if either the array itself or
281304
any of the subscript expressions are null. Also, null is returned if a
@@ -391,6 +414,10 @@ UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'
391414
WHERE name = 'Carol';
392415
</programlisting>
393416

417+
The slice syntaxes with omitted <replaceable>lower-bound</replaceable> and/or
418+
<replaceable>upper-bound</replaceable> can be used too, but only when
419+
updating an array value that is not NULL or zero-dimensional (otherwise,
420+
there is no existing subscript limit to substitute).
394421
</para>
395422

396423
<para>

‎src/backend/executor/execQual.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
271271
j=0;
272272
IntArrayupper,
273273
lower;
274+
boolupperProvided[MAXDIM],
275+
lowerProvided[MAXDIM];
274276
int*lIndex;
275277

276278
array_source=ExecEvalExpr(astate->refexpr,
@@ -300,6 +302,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
300302
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
301303
i+1,MAXDIM)));
302304

305+
if (eltstate==NULL)
306+
{
307+
/* Slice bound is omitted, so use array's upper bound */
308+
Assert(astate->reflowerindexpr!=NIL);
309+
upperProvided[i++]= false;
310+
continue;
311+
}
312+
upperProvided[i]= true;
313+
303314
upper.indx[i++]=DatumGetInt32(ExecEvalExpr(eltstate,
304315
econtext,
305316
&eisnull,
@@ -328,6 +339,14 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
328339
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
329340
j+1,MAXDIM)));
330341

342+
if (eltstate==NULL)
343+
{
344+
/* Slice bound is omitted, so use array's lower bound */
345+
lowerProvided[j++]= false;
346+
continue;
347+
}
348+
lowerProvided[j]= true;
349+
331350
lower.indx[j++]=DatumGetInt32(ExecEvalExpr(eltstate,
332351
econtext,
333352
&eisnull,
@@ -398,6 +417,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
398417
econtext->caseValue_datum=
399418
array_get_slice(array_source,i,
400419
upper.indx,lower.indx,
420+
upperProvided,lowerProvided,
401421
astate->refattrlength,
402422
astate->refelemlength,
403423
astate->refelembyval,
@@ -456,6 +476,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
456476
else
457477
returnarray_set_slice(array_source,i,
458478
upper.indx,lower.indx,
479+
upperProvided,lowerProvided,
459480
sourceData,
460481
eisnull,
461482
astate->refattrlength,
@@ -475,6 +496,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
475496
else
476497
returnarray_get_slice(array_source,i,
477498
upper.indx,lower.indx,
499+
upperProvided,lowerProvided,
478500
astate->refattrlength,
479501
astate->refelemlength,
480502
astate->refelembyval,

‎src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,6 +2401,7 @@ _copyAIndices(const A_Indices *from)
24012401
{
24022402
A_Indices*newnode=makeNode(A_Indices);
24032403

2404+
COPY_SCALAR_FIELD(is_slice);
24042405
COPY_NODE_FIELD(lidx);
24052406
COPY_NODE_FIELD(uidx);
24062407

‎src/backend/nodes/equalfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,6 +2151,7 @@ _equalAStar(const A_Star *a, const A_Star *b)
21512151
staticbool
21522152
_equalAIndices(constA_Indices*a,constA_Indices*b)
21532153
{
2154+
COMPARE_SCALAR_FIELD(is_slice);
21542155
COMPARE_NODE_FIELD(lidx);
21552156
COMPARE_NODE_FIELD(uidx);
21562157

‎src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2763,6 +2763,7 @@ _outA_Indices(StringInfo str, const A_Indices *node)
27632763
{
27642764
WRITE_NODE_TYPE("A_INDICES");
27652765

2766+
WRITE_BOOL_FIELD(is_slice);
27662767
WRITE_NODE_FIELD(lidx);
27672768
WRITE_NODE_FIELD(uidx);
27682769
}

‎src/backend/parser/gram.y

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
434434
%type<node>columnDefcolumnOptions
435435
%type<defelt>def_elemreloption_elemold_aggr_elemoperator_def_elem
436436
%type<node>def_argcolumnElemwhere_clausewhere_or_current_clause
437-
a_exprb_exprc_exprAexprConstindirection_el
437+
a_exprb_exprc_exprAexprConstindirection_elopt_slice_bound
438438
columnrefin_exprhaving_clausefunc_tablearray_expr
439439
ExclusionWhereClause
440440
%type<list>rowsfrom_itemrowsfrom_listopt_col_def_list
@@ -13191,19 +13191,26 @@ indirection_el:
1319113191
|'[' a_expr']'
1319213192
{
1319313193
A_Indices *ai =makeNode(A_Indices);
13194+
ai->is_slice =false;
1319413195
ai->lidx =NULL;
1319513196
ai->uidx = $2;
1319613197
$$ = (Node *) ai;
1319713198
}
13198-
|'['a_expr':'a_expr']'
13199+
|'['opt_slice_bound':'opt_slice_bound']'
1319913200
{
1320013201
A_Indices *ai =makeNode(A_Indices);
13202+
ai->is_slice =true;
1320113203
ai->lidx = $2;
1320213204
ai->uidx = $4;
1320313205
$$ = (Node *) ai;
1320413206
}
1320513207
;
1320613208

13209+
opt_slice_bound:
13210+
a_expr{ $$ = $1; }
13211+
|/*EMPTY*/{ $$ =NULL; }
13212+
;
13213+
1320713214
indirection:
1320813215
indirection_el{ $$ =list_make1($1); }
1320913216
| indirection indirection_el{ $$ =lappend($1, $2); }

‎src/backend/parser/parse_node.c

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -311,18 +311,18 @@ transformArraySubscripts(ParseState *pstate,
311311
elementType=transformArrayType(&arrayType,&arrayTypMod);
312312

313313
/*
314-
* A list containing onlysingle subscripts refers to a single array
315-
* element. If any of the items aredouble subscripts (lower:upper), then
316-
* the subscript expression means an array slice operation. In this case,
317-
* wesupply a default lower bound of 1 for any items that contain only a
318-
*singlesubscript. We have to prescan the indirection list to see if
319-
* there are anydouble subscripts.
314+
* A list containing onlysimple subscripts refers to a single array
315+
* element. If any of the items areslice specifiers (lower:upper), then
316+
* the subscript expression means an array slice operation.In this case,
317+
* weconvert any non-slice items to slices by treating the single
318+
* subscript as the upper bound and supplying an assumed lower bound of 1.
319+
*We have to prescan the list to see ifthere are anyslice items.
320320
*/
321321
foreach(idx,indirection)
322322
{
323323
A_Indices*ai= (A_Indices*)lfirst(idx);
324324

325-
if (ai->lidx!=NULL)
325+
if (ai->is_slice)
326326
{
327327
isSlice= true;
328328
break;
@@ -356,7 +356,7 @@ transformArraySubscripts(ParseState *pstate,
356356
errmsg("array subscript must have type integer"),
357357
parser_errposition(pstate,exprLocation(ai->lidx))));
358358
}
359-
else
359+
elseif (!ai->is_slice)
360360
{
361361
/* Make a constant 1 */
362362
subexpr= (Node*)makeConst(INT4OID,
@@ -367,21 +367,38 @@ transformArraySubscripts(ParseState *pstate,
367367
false,
368368
true);/* pass by value */
369369
}
370+
else
371+
{
372+
/* Slice with omitted lower bound, put NULL into the list */
373+
subexpr=NULL;
374+
}
370375
lowerIndexpr=lappend(lowerIndexpr,subexpr);
371376
}
372-
subexpr=transformExpr(pstate,ai->uidx,pstate->p_expr_kind);
373-
/* If it's not int4 already, try to coerce */
374-
subexpr=coerce_to_target_type(pstate,
375-
subexpr,exprType(subexpr),
376-
INT4OID,-1,
377-
COERCION_ASSIGNMENT,
378-
COERCE_IMPLICIT_CAST,
379-
-1);
380-
if (subexpr==NULL)
381-
ereport(ERROR,
382-
(errcode(ERRCODE_DATATYPE_MISMATCH),
383-
errmsg("array subscript must have type integer"),
384-
parser_errposition(pstate,exprLocation(ai->uidx))));
377+
else
378+
Assert(ai->lidx==NULL&& !ai->is_slice);
379+
380+
if (ai->uidx)
381+
{
382+
subexpr=transformExpr(pstate,ai->uidx,pstate->p_expr_kind);
383+
/* If it's not int4 already, try to coerce */
384+
subexpr=coerce_to_target_type(pstate,
385+
subexpr,exprType(subexpr),
386+
INT4OID,-1,
387+
COERCION_ASSIGNMENT,
388+
COERCE_IMPLICIT_CAST,
389+
-1);
390+
if (subexpr==NULL)
391+
ereport(ERROR,
392+
(errcode(ERRCODE_DATATYPE_MISMATCH),
393+
errmsg("array subscript must have type integer"),
394+
parser_errposition(pstate,exprLocation(ai->uidx))));
395+
}
396+
else
397+
{
398+
/* Slice with omitted upper bound, put NULL into the list */
399+
Assert(isSlice&&ai->is_slice);
400+
subexpr=NULL;
401+
}
385402
upperIndexpr=lappend(upperIndexpr,subexpr);
386403
}
387404

‎src/backend/parser/parse_target.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ transformAssignmentIndirection(ParseState *pstate,
650650
if (IsA(n,A_Indices))
651651
{
652652
subscripts=lappend(subscripts,n);
653-
if (((A_Indices*)n)->lidx!=NULL)
653+
if (((A_Indices*)n)->is_slice)
654654
isSlice= true;
655655
}
656656
elseif (IsA(n,A_Star))

‎src/backend/utils/adt/arrayfuncs.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,8 @@ array_get_element_expanded(Datum arraydatum,
19951995
*nSubscripts: number of subscripts supplied (must be same for upper/lower)
19961996
*upperIndx[]: the upper subscript values
19971997
*lowerIndx[]: the lower subscript values
1998+
*upperProvided[]: true for provided upper subscript values
1999+
*lowerProvided[]: true for provided lower subscript values
19982000
*arraytyplen: pg_type.typlen for the array type
19992001
*elmlen: pg_type.typlen for the array's element type
20002002
*elmbyval: pg_type.typbyval for the array's element type
@@ -2003,6 +2005,9 @@ array_get_element_expanded(Datum arraydatum,
20032005
* Outputs:
20042006
*The return value is the new array Datum (it's never NULL)
20052007
*
2008+
* Omitted upper and lower subscript values are replaced by the corresponding
2009+
* array bound.
2010+
*
20062011
* NOTE: we assume it is OK to scribble on the provided subscript arrays
20072012
* lowerIndx[] and upperIndx[]. These are generally just temporaries.
20082013
*/
@@ -2011,6 +2016,8 @@ array_get_slice(Datum arraydatum,
20112016
intnSubscripts,
20122017
int*upperIndx,
20132018
int*lowerIndx,
2019+
bool*upperProvided,
2020+
bool*lowerProvided,
20142021
intarraytyplen,
20152022
intelmlen,
20162023
boolelmbyval,
@@ -2081,9 +2088,9 @@ array_get_slice(Datum arraydatum,
20812088

20822089
for (i=0;i<nSubscripts;i++)
20832090
{
2084-
if (lowerIndx[i]<lb[i])
2091+
if (!lowerProvided[i]||lowerIndx[i]<lb[i])
20852092
lowerIndx[i]=lb[i];
2086-
if (upperIndx[i] >= (dim[i]+lb[i]))
2093+
if (!upperProvided[i]||upperIndx[i] >= (dim[i]+lb[i]))
20872094
upperIndx[i]=dim[i]+lb[i]-1;
20882095
if (lowerIndx[i]>upperIndx[i])
20892096
returnPointerGetDatum(construct_empty_array(elemtype));
@@ -2708,6 +2715,8 @@ array_set_element_expanded(Datum arraydatum,
27082715
*nSubscripts: number of subscripts supplied (must be same for upper/lower)
27092716
*upperIndx[]: the upper subscript values
27102717
*lowerIndx[]: the lower subscript values
2718+
*upperProvided[]: true for provided upper subscript values
2719+
*lowerProvided[]: true for provided lower subscript values
27112720
*srcArrayDatum: the source for the inserted values
27122721
*isNull: indicates whether srcArrayDatum is NULL
27132722
*arraytyplen: pg_type.typlen for the array type
@@ -2719,6 +2728,9 @@ array_set_element_expanded(Datum arraydatum,
27192728
* A new array is returned, just like the old except for the
27202729
* modified range. The original array object is not changed.
27212730
*
2731+
* Omitted upper and lower subscript values are replaced by the corresponding
2732+
* array bound.
2733+
*
27222734
* For one-dimensional arrays only, we allow the array to be extended
27232735
* by assigning to positions outside the existing subscript range; any
27242736
* positions between the existing elements and the new ones are set to NULLs.
@@ -2735,6 +2747,8 @@ array_set_slice(Datum arraydatum,
27352747
intnSubscripts,
27362748
int*upperIndx,
27372749
int*lowerIndx,
2750+
bool*upperProvided,
2751+
bool*lowerProvided,
27382752
DatumsrcArrayDatum,
27392753
boolisNull,
27402754
intarraytyplen,
@@ -2806,6 +2820,13 @@ array_set_slice(Datum arraydatum,
28062820

28072821
for (i=0;i<nSubscripts;i++)
28082822
{
2823+
if (!upperProvided[i]|| !lowerProvided[i])
2824+
ereport(ERROR,
2825+
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2826+
errmsg("array slice subscript must provide both boundaries"),
2827+
errdetail("When assigning to a slice of an empty array value,"
2828+
" slice boundaries must be fully specified.")));
2829+
28092830
dim[i]=1+upperIndx[i]-lowerIndx[i];
28102831
lb[i]=lowerIndx[i];
28112832
}
@@ -2839,6 +2860,10 @@ array_set_slice(Datum arraydatum,
28392860
if (ndim==1)
28402861
{
28412862
Assert(nSubscripts==1);
2863+
if (!lowerProvided[0])
2864+
lowerIndx[0]=lb[0];
2865+
if (!upperProvided[0])
2866+
upperIndx[0]=dim[0]+lb[0]-1;
28422867
if (lowerIndx[0]>upperIndx[0])
28432868
ereport(ERROR,
28442869
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
@@ -2867,6 +2892,10 @@ array_set_slice(Datum arraydatum,
28672892
*/
28682893
for (i=0;i<nSubscripts;i++)
28692894
{
2895+
if (!lowerProvided[i])
2896+
lowerIndx[i]=lb[i];
2897+
if (!upperProvided[i])
2898+
upperIndx[i]=dim[i]+lb[i]-1;
28702899
if (lowerIndx[i]>upperIndx[i])
28712900
ereport(ERROR,
28722901
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),

‎src/backend/utils/adt/ruleutils.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9372,10 +9372,12 @@ printSubscripts(ArrayRef *aref, deparse_context *context)
93729372
appendStringInfoChar(buf,'[');
93739373
if (lowlist_item)
93749374
{
9375+
/* If subexpression is NULL, get_rule_expr prints nothing */
93759376
get_rule_expr((Node*)lfirst(lowlist_item),context, false);
93769377
appendStringInfoChar(buf,':');
93779378
lowlist_item=lnext(lowlist_item);
93789379
}
9380+
/* If subexpression is NULL, get_rule_expr prints nothing */
93799381
get_rule_expr((Node*)lfirst(uplist_item),context, false);
93809382
appendStringInfoChar(buf,']');
93819383
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp