88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.131 2006/09/10 20:14:20 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.132 2006/09/29 21:22:21 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -1925,8 +1925,9 @@ array_get_slice(ArrayType *array,
19251925 * modified entry. The original array object is not changed.
19261926 *
19271927 * For one-dimensional arrays only, we allow the array to be extended
1928- * by assigning to the position one above or one below the existing range.
1929- * (XXX we could be more flexible: perhaps allow NULL fill?)
1928+ * by assigning to a position outside the existing subscript range; any
1929+ * positions between the existing elements and the new one are set to NULLs.
1930+ * (XXX TODO: allow a corresponding behavior for multidimensional arrays)
19301931 *
19311932 * NOTE: For assignments, we throw an error for invalid subscripts etc,
19321933 * rather than returning a NULL as the fetch operations do.
@@ -1949,17 +1950,18 @@ array_set(ArrayType *array,
19491950lb [MAXDIM ],
19501951offset ;
19511952char * elt_ptr ;
1952- bool extendbefore = false;
1953- bool extendafter = false;
19541953bool newhasnulls ;
19551954bits8 * oldnullbitmap ;
19561955int oldnitems ,
1956+ newnitems ,
19571957olddatasize ,
19581958newsize ,
19591959olditemlen ,
19601960newitemlen ,
19611961overheadlen ,
19621962oldoverheadlen ,
1963+ addedbefore ,
1964+ addedafter ,
19631965lenbefore ,
19641966lenafter ;
19651967
@@ -1972,12 +1974,12 @@ array_set(ArrayType *array,
19721974if (nSubscripts != 1 )
19731975ereport (ERROR ,
19741976(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
1975- errmsg ("invalid array subscripts" )));
1977+ errmsg ("wrong number of array subscripts" )));
19761978
19771979if (indx [0 ]< 0 || indx [0 ]* elmlen >=arraytyplen )
19781980ereport (ERROR ,
19791981(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
1980- errmsg ("invalid arraysubscripts " )));
1982+ errmsg ("arraysubscript out of range " )));
19811983
19821984if (isNull )
19831985ereport (ERROR ,
@@ -1994,7 +1996,7 @@ array_set(ArrayType *array,
19941996if (nSubscripts <=0 || nSubscripts > MAXDIM )
19951997ereport (ERROR ,
19961998(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
1997- errmsg ("invalid array subscripts" )));
1999+ errmsg ("wrong number of array subscripts" )));
19982000
19992001/* make sure item to be inserted is not toasted */
20002002if (elmlen == -1 && !isNull )
@@ -2028,70 +2030,72 @@ array_set(ArrayType *array,
20282030if (ndim != nSubscripts )
20292031ereport (ERROR ,
20302032(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2031- errmsg ("invalid array subscripts" )));
2033+ errmsg ("wrong number of array subscripts" )));
20322034
20332035/* copy dim/lb since we may modify them */
20342036memcpy (dim ,ARR_DIMS (array ),ndim * sizeof (int ));
20352037memcpy (lb ,ARR_LBOUND (array ),ndim * sizeof (int ));
20362038
2039+ newhasnulls = (ARR_HASNULL (array )|| isNull );
2040+ addedbefore = addedafter = 0 ;
2041+
20372042/*
20382043 * Check subscripts
20392044 */
2040- for ( i = 0 ; i < ndim ; i ++ )
2045+ if ( ndim == 1 )
20412046{
2042- if (indx [i ]< lb [i ])
2047+ if (indx [0 ]< lb [0 ])
20432048{
2044- if (ndim == 1 && indx [i ]== lb [i ]- 1 )
2045- {
2046- dim [i ]++ ;
2047- lb [i ]-- ;
2048- extendbefore = true;
2049- }
2050- else
2051- ereport (ERROR ,
2052- (errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2053- errmsg ("invalid array subscripts" )));
2049+ addedbefore = lb [0 ]- indx [0 ];
2050+ dim [0 ]+= addedbefore ;
2051+ lb [0 ]= indx [0 ];
2052+ if (addedbefore > 1 )
2053+ newhasnulls = true;/* will insert nulls */
20542054}
2055- if (indx [i ] >= (dim [i ]+ lb [i ]))
2055+ if (indx [0 ] >= (dim [0 ]+ lb [0 ]))
20562056{
2057- if (ndim == 1 && indx [i ]== (dim [i ]+ lb [i ]))
2058- {
2059- dim [i ]++ ;
2060- extendafter = true;
2061- }
2062- else
2057+ addedafter = indx [0 ]- (dim [0 ]+ lb [0 ])+ 1 ;
2058+ dim [0 ]+= addedafter ;
2059+ if (addedafter > 1 )
2060+ newhasnulls = true;/* will insert nulls */
2061+ }
2062+ }
2063+ else
2064+ {
2065+ /*
2066+ * XXX currently we do not support extending multi-dimensional
2067+ * arrays during assignment
2068+ */
2069+ for (i = 0 ;i < ndim ;i ++ )
2070+ {
2071+ if (indx [i ]< lb [i ]||
2072+ indx [i ] >= (dim [i ]+ lb [i ]))
20632073ereport (ERROR ,
20642074(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2065- errmsg ("invalid arraysubscripts " )));
2075+ errmsg ("arraysubscript out of range " )));
20662076}
20672077}
20682078
20692079/*
20702080 * Compute sizes of items and areas to copy
20712081 */
2072- if (ARR_HASNULL (array )|| isNull )
2073- {
2074- newhasnulls = true;
2075- overheadlen = ARR_OVERHEAD_WITHNULLS (ndim ,
2076- ArrayGetNItems (ndim ,dim ));
2077- }
2082+ newnitems = ArrayGetNItems (ndim ,dim );
2083+ if (newhasnulls )
2084+ overheadlen = ARR_OVERHEAD_WITHNULLS (ndim ,newnitems );
20782085else
2079- {
2080- newhasnulls = false;
20812086overheadlen = ARR_OVERHEAD_NONULLS (ndim );
2082- }
20832087oldnitems = ArrayGetNItems (ndim ,ARR_DIMS (array ));
20842088oldnullbitmap = ARR_NULLBITMAP (array );
20852089oldoverheadlen = ARR_DATA_OFFSET (array );
20862090olddatasize = ARR_SIZE (array )- oldoverheadlen ;
2087- if (extendbefore )
2091+ if (addedbefore )
20882092{
20892093offset = 0 ;
20902094lenbefore = 0 ;
20912095olditemlen = 0 ;
20922096lenafter = olddatasize ;
20932097}
2094- else if (extendafter )
2098+ else if (addedafter )
20952099{
20962100offset = oldnitems ;
20972101lenbefore = olddatasize ;
@@ -2158,17 +2162,24 @@ array_set(ArrayType *array,
21582162{
21592163bits8 * newnullbitmap = ARR_NULLBITMAP (newarray );
21602164
2161- array_set_isnull (newnullbitmap ,offset ,isNull );
2162- if (extendbefore )
2163- array_bitmap_copy (newnullbitmap ,1 ,
2165+ /* Zero the bitmap to take care of marking inserted positions null */
2166+ MemSet (newnullbitmap ,0 , (newnitems + 7 ) /8 );
2167+ /* Fix the inserted value */
2168+ if (addedafter )
2169+ array_set_isnull (newnullbitmap ,newnitems - 1 ,isNull );
2170+ else
2171+ array_set_isnull (newnullbitmap ,offset ,isNull );
2172+ /* Fix the copied range(s) */
2173+ if (addedbefore )
2174+ array_bitmap_copy (newnullbitmap ,addedbefore ,
21642175oldnullbitmap ,0 ,
21652176oldnitems );
21662177else
21672178{
21682179array_bitmap_copy (newnullbitmap ,0 ,
21692180oldnullbitmap ,0 ,
21702181offset );
2171- if (! extendafter )
2182+ if (addedafter == 0 )
21722183array_bitmap_copy (newnullbitmap ,offset + 1 ,
21732184oldnullbitmap ,offset + 1 ,
21742185oldnitems - offset - 1 );
@@ -2202,6 +2213,11 @@ array_set(ArrayType *array,
22022213 * A new array is returned, just like the old except for the
22032214 * modified range. The original array object is not changed.
22042215 *
2216+ * For one-dimensional arrays only, we allow the array to be extended
2217+ * by assigning to positions outside the existing subscript range; any
2218+ * positions between the existing elements and the new ones are set to NULLs.
2219+ * (XXX TODO: allow a corresponding behavior for multidimensional arrays)
2220+ *
22052221 * NOTE: we assume it is OK to scribble on the provided index arrays
22062222 * lowerIndx[] and upperIndx[]. These are generally just temporaries.
22072223 *
@@ -2235,6 +2251,8 @@ array_set_slice(ArrayType *array,
22352251newitemsize ,
22362252overheadlen ,
22372253oldoverheadlen ,
2254+ addedbefore ,
2255+ addedafter ,
22382256lenbefore ,
22392257lenafter ,
22402258itemsbefore ,
@@ -2298,55 +2316,70 @@ array_set_slice(ArrayType *array,
22982316if (ndim < nSubscripts || ndim <=0 || ndim > MAXDIM )
22992317ereport (ERROR ,
23002318(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2301- errmsg ("invalid array subscripts" )));
2319+ errmsg ("wrong number of array subscripts" )));
23022320
23032321/* copy dim/lb since we may modify them */
23042322memcpy (dim ,ARR_DIMS (array ),ndim * sizeof (int ));
23052323memcpy (lb ,ARR_LBOUND (array ),ndim * sizeof (int ));
23062324
2325+ newhasnulls = (ARR_HASNULL (array )|| ARR_HASNULL (srcArray ));
2326+ addedbefore = addedafter = 0 ;
2327+
23072328/*
2308- * Check provided subscripts. A slice exceeding the current array limits
2309- * throws an error, *except* in the 1-D case where we will extend the
2310- * array as long as no hole is created. An empty slice is an error, too.
2329+ * Check subscripts
23112330 */
2312- for ( i = 0 ; i < nSubscripts ; i ++ )
2331+ if ( ndim == 1 )
23132332{
2314- if (lowerIndx [i ]> upperIndx [i ])
2333+ Assert (nSubscripts == 1 );
2334+ if (lowerIndx [0 ]> upperIndx [0 ])
23152335ereport (ERROR ,
23162336(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2317- errmsg ("invalid array subscripts " )));
2318- if (lowerIndx [i ]< lb [i ])
2337+ errmsg ("upper bound cannot be less than lower bound " )));
2338+ if (lowerIndx [0 ]< lb [0 ])
23192339{
2320- if (ndim == 1 && upperIndx [i ] >=lb [i ]- 1 )
2321- {
2322- dim [i ]+= lb [i ]- lowerIndx [i ];
2323- lb [i ]= lowerIndx [i ];
2324- }
2325- else
2340+ if (upperIndx [0 ]< lb [0 ]- 1 )
2341+ newhasnulls = true;/* will insert nulls */
2342+ addedbefore = lb [0 ]- lowerIndx [0 ];
2343+ dim [0 ]+= addedbefore ;
2344+ lb [0 ]= lowerIndx [0 ];
2345+ }
2346+ if (upperIndx [0 ] >= (dim [0 ]+ lb [0 ]))
2347+ {
2348+ if (lowerIndx [0 ]> (dim [0 ]+ lb [0 ]))
2349+ newhasnulls = true;/* will insert nulls */
2350+ addedafter = upperIndx [0 ]- (dim [0 ]+ lb [0 ])+ 1 ;
2351+ dim [0 ]+= addedafter ;
2352+ }
2353+ }
2354+ else
2355+ {
2356+ /*
2357+ * XXX currently we do not support extending multi-dimensional
2358+ * arrays during assignment
2359+ */
2360+ for (i = 0 ;i < nSubscripts ;i ++ )
2361+ {
2362+ if (lowerIndx [i ]> upperIndx [i ])
2363+ ereport (ERROR ,
2364+ (errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2365+ errmsg ("upper bound cannot be less than lower bound" )));
2366+ if (lowerIndx [i ]< lb [i ]||
2367+ upperIndx [i ] >= (dim [i ]+ lb [i ]))
23262368ereport (ERROR ,
23272369(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2328- errmsg ("invalid arraysubscripts " )));
2370+ errmsg ("arraysubscript out of range " )));
23292371}
2330- if (upperIndx [i ] >= (dim [i ]+ lb [i ]))
2372+ /* fill any missing subscript positions with full array range */
2373+ for (;i < ndim ;i ++ )
23312374{
2332- if ( ndim == 1 && lowerIndx [i ]<= ( dim [ i ] + lb [i ]))
2333- dim [i ]= upperIndx [i ]- lb [i ]+ 1 ;
2334- else
2375+ lowerIndx [i ]= lb [i ];
2376+ upperIndx [i ]= dim [i ]+ lb [i ]- 1 ;
2377+ if ( lowerIndx [ i ] > upperIndx [ i ])
23352378ereport (ERROR ,
23362379(errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2337- errmsg ("invalid array subscripts " )));
2380+ errmsg ("upper bound cannot be less than lower bound " )));
23382381}
23392382}
2340- /* fill any missing subscript positions with full array range */
2341- for (;i < ndim ;i ++ )
2342- {
2343- lowerIndx [i ]= lb [i ];
2344- upperIndx [i ]= dim [i ]+ lb [i ]- 1 ;
2345- if (lowerIndx [i ]> upperIndx [i ])
2346- ereport (ERROR ,
2347- (errcode (ERRCODE_ARRAY_SUBSCRIPT_ERROR ),
2348- errmsg ("invalid array subscripts" )));
2349- }
23502383
23512384/* Do this mainly to check for overflow */
23522385nitems = ArrayGetNItems (ndim ,dim );
@@ -2366,16 +2399,10 @@ array_set_slice(ArrayType *array,
23662399 * Compute space occupied by new entries, space occupied by replaced
23672400 * entries, and required space for new array.
23682401 */
2369- if (ARR_HASNULL (array )|| ARR_HASNULL (srcArray ))
2370- {
2371- newhasnulls = true;
2402+ if (newhasnulls )
23722403overheadlen = ARR_OVERHEAD_WITHNULLS (ndim ,nitems );
2373- }
23742404else
2375- {
2376- newhasnulls = false;
23772405overheadlen = ARR_OVERHEAD_NONULLS (ndim );
2378- }
23792406newitemsize = array_nelems_size (ARR_DATA_PTR (srcArray ),0 ,
23802407ARR_NULLBITMAP (srcArray ),nsrcitems ,
23812408elmlen ,elmbyval ,elmalign );
@@ -2407,7 +2434,7 @@ array_set_slice(ArrayType *array,
24072434char * oldarraydata = ARR_DATA_PTR (array );
24082435bits8 * oldarraybitmap = ARR_NULLBITMAP (array );
24092436
2410- itemsbefore = slicelb - oldlb ;
2437+ itemsbefore = Min ( slicelb , oldub + 1 ) - oldlb ;
24112438lenbefore = array_nelems_size (oldarraydata ,0 ,oldarraybitmap ,
24122439itemsbefore ,
24132440elmlen ,elmbyval ,elmalign );
@@ -2467,13 +2494,15 @@ array_set_slice(ArrayType *array,
24672494bits8 * newnullbitmap = ARR_NULLBITMAP (newarray );
24682495bits8 * oldnullbitmap = ARR_NULLBITMAP (array );
24692496
2470- array_bitmap_copy (newnullbitmap ,0 ,
2497+ /* Zero the bitmap to handle marking inserted positions null */
2498+ MemSet (newnullbitmap ,0 , (nitems + 7 ) /8 );
2499+ array_bitmap_copy (newnullbitmap ,addedbefore ,
24712500oldnullbitmap ,0 ,
24722501itemsbefore );
2473- array_bitmap_copy (newnullbitmap ,itemsbefore ,
2502+ array_bitmap_copy (newnullbitmap ,lowerIndx [ 0 ] - lb [ 0 ] ,
24742503ARR_NULLBITMAP (srcArray ),0 ,
24752504nsrcitems );
2476- array_bitmap_copy (newnullbitmap ,itemsbefore + nsrcitems ,
2505+ array_bitmap_copy (newnullbitmap ,addedbefore + itemsbefore + nolditems ,
24772506oldnullbitmap ,itemsbefore + nolditems ,
24782507itemsafter );
24792508}