|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.145 2008/05/12 00:00:51 alvherre Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.146 2008/07/16 00:48:53 momjian Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -95,6 +95,11 @@ static void array_insert_slice(ArrayType *destArray, ArrayType *origArray,
|
95 | 95 | int*st,int*endp,
|
96 | 96 | inttyplen,booltypbyval,chartypalign);
|
97 | 97 | staticintarray_cmp(FunctionCallInfofcinfo);
|
| 98 | +staticArrayType*create_array_envelope(intndims,int*dimv,int*lbv,intnbytes, |
| 99 | +Oidelmtype,intdataoffset); |
| 100 | +staticArrayType*array_fill_internal(ArrayType*dims,ArrayType*lbs,Datumvalue, |
| 101 | +Oidelmtype,boolisnull, |
| 102 | +FunctionCallInfofcinfo); |
98 | 103 |
|
99 | 104 |
|
100 | 105 | /*
|
@@ -4314,3 +4319,272 @@ generate_subscripts_nodir(PG_FUNCTION_ARGS)
|
4314 | 4319 | /* just call the other one -- it can handle both cases */
|
4315 | 4320 | returngenerate_subscripts(fcinfo);
|
4316 | 4321 | }
|
| 4322 | + |
| 4323 | +/* |
| 4324 | + * array_fill_with_lower_bounds |
| 4325 | + *Create and fill array with defined lower bounds. |
| 4326 | + */ |
| 4327 | +Datum |
| 4328 | +array_fill_with_lower_bounds(PG_FUNCTION_ARGS) |
| 4329 | +{ |
| 4330 | +ArrayType*dims; |
| 4331 | +ArrayType*lbs; |
| 4332 | +ArrayType*result; |
| 4333 | +Oidelmtype; |
| 4334 | +Datumvalue; |
| 4335 | +boolisnull; |
| 4336 | + |
| 4337 | +if (PG_ARGISNULL(1)||PG_ARGISNULL(2)) |
| 4338 | +ereport(ERROR, |
| 4339 | + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
| 4340 | +errmsg("dimension array or low bound array cannot be NULL"))); |
| 4341 | + |
| 4342 | +dims=PG_GETARG_ARRAYTYPE_P(1); |
| 4343 | +lbs=PG_GETARG_ARRAYTYPE_P(2); |
| 4344 | + |
| 4345 | +if (!PG_ARGISNULL(0)) |
| 4346 | +{ |
| 4347 | +value=PG_GETARG_DATUM(0); |
| 4348 | +isnull= false; |
| 4349 | +} |
| 4350 | +else |
| 4351 | +{ |
| 4352 | +value=0; |
| 4353 | +isnull= true; |
| 4354 | +} |
| 4355 | + |
| 4356 | +elmtype=get_fn_expr_argtype(fcinfo->flinfo,0); |
| 4357 | +if (!OidIsValid(elmtype)) |
| 4358 | +elog(ERROR,"could not determine data type of input"); |
| 4359 | + |
| 4360 | +result=array_fill_internal(dims,lbs,value,elmtype,isnull,fcinfo); |
| 4361 | +PG_RETURN_ARRAYTYPE_P(result); |
| 4362 | +} |
| 4363 | + |
| 4364 | +/* |
| 4365 | + * array_fill |
| 4366 | + *Create and fill array with default lower bounds. |
| 4367 | + */ |
| 4368 | +Datum |
| 4369 | +array_fill(PG_FUNCTION_ARGS) |
| 4370 | +{ |
| 4371 | +ArrayType*dims; |
| 4372 | +ArrayType*result; |
| 4373 | +Oidelmtype; |
| 4374 | +Datumvalue; |
| 4375 | +boolisnull; |
| 4376 | + |
| 4377 | +if (PG_ARGISNULL(1)) |
| 4378 | +ereport(ERROR, |
| 4379 | + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
| 4380 | +errmsg("dimension array or low bound array cannot be NULL"))); |
| 4381 | + |
| 4382 | +dims=PG_GETARG_ARRAYTYPE_P(1); |
| 4383 | + |
| 4384 | +if (!PG_ARGISNULL(0)) |
| 4385 | +{ |
| 4386 | +value=PG_GETARG_DATUM(0); |
| 4387 | +isnull= false; |
| 4388 | +} |
| 4389 | +else |
| 4390 | +{ |
| 4391 | +value=0; |
| 4392 | +isnull= true; |
| 4393 | +} |
| 4394 | + |
| 4395 | +elmtype=get_fn_expr_argtype(fcinfo->flinfo,0); |
| 4396 | +if (!OidIsValid(elmtype)) |
| 4397 | +elog(ERROR,"could not determine data type of input"); |
| 4398 | + |
| 4399 | +result=array_fill_internal(dims,NULL,value,elmtype,isnull,fcinfo); |
| 4400 | +PG_RETURN_ARRAYTYPE_P(result); |
| 4401 | +} |
| 4402 | + |
| 4403 | +staticArrayType* |
| 4404 | +create_array_envelope(intndims,int*dimv,int*lbsv,intnbytes, |
| 4405 | +Oidelmtype,intdataoffset) |
| 4406 | +{ |
| 4407 | +ArrayType*result; |
| 4408 | + |
| 4409 | +result= (ArrayType*)palloc0(nbytes); |
| 4410 | +SET_VARSIZE(result,nbytes); |
| 4411 | +result->ndim=ndims; |
| 4412 | +result->dataoffset=dataoffset; |
| 4413 | +result->elemtype=elmtype; |
| 4414 | +memcpy(ARR_DIMS(result),dimv,ndims*sizeof(int)); |
| 4415 | +memcpy(ARR_LBOUND(result),lbsv,ndims*sizeof(int)); |
| 4416 | + |
| 4417 | +returnresult; |
| 4418 | +} |
| 4419 | + |
| 4420 | +staticArrayType* |
| 4421 | +array_fill_internal(ArrayType*dims,ArrayType*lbs,Datumvalue, |
| 4422 | +Oidelmtype,boolisnull, |
| 4423 | +FunctionCallInfofcinfo) |
| 4424 | +{ |
| 4425 | +ArrayType*result; |
| 4426 | +int*dimv; |
| 4427 | +int*lbsv; |
| 4428 | +intndims; |
| 4429 | +intnitems; |
| 4430 | +intdeflbs[MAXDIM]; |
| 4431 | +int16elmlen; |
| 4432 | +boolelmbyval; |
| 4433 | +charelmalign; |
| 4434 | +ArrayMetaState*my_extra; |
| 4435 | + |
| 4436 | +/* |
| 4437 | + * Params checks |
| 4438 | + */ |
| 4439 | +if (ARR_NDIM(dims)!=1) |
| 4440 | +ereport(ERROR, |
| 4441 | + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), |
| 4442 | +errmsg("wrong number of array subscripts"), |
| 4443 | +errhint("Dimension array must be one dimensional."))); |
| 4444 | + |
| 4445 | +if (ARR_LBOUND(dims)[0]!=1) |
| 4446 | +ereport(ERROR, |
| 4447 | + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), |
| 4448 | +errmsg("wrong range of array_subscripts"), |
| 4449 | +errhint("Lower bound of dimension array must be one."))); |
| 4450 | + |
| 4451 | +if (ARR_HASNULL(dims)) |
| 4452 | +ereport(ERROR, |
| 4453 | + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
| 4454 | +errmsg("dimension values cannot be null"))); |
| 4455 | + |
| 4456 | +dimv= (int*)ARR_DATA_PTR(dims); |
| 4457 | +ndims=ARR_DIMS(dims)[0]; |
| 4458 | + |
| 4459 | +if (ndims<0)/* we do allow zero-dimension arrays */ |
| 4460 | +ereport(ERROR, |
| 4461 | +(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 4462 | +errmsg("invalid number of dimensions: %d",ndims))); |
| 4463 | +if (ndims>MAXDIM) |
| 4464 | +ereport(ERROR, |
| 4465 | +(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
| 4466 | +errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", |
| 4467 | +ndims,MAXDIM))); |
| 4468 | + |
| 4469 | +if (lbs!=NULL) |
| 4470 | +{ |
| 4471 | +if (ARR_NDIM(lbs)!=1) |
| 4472 | +ereport(ERROR, |
| 4473 | + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), |
| 4474 | +errmsg("wrong number of array subscripts"), |
| 4475 | +errhint("Dimension array must be one dimensional."))); |
| 4476 | + |
| 4477 | +if (ARR_LBOUND(lbs)[0]!=1) |
| 4478 | +ereport(ERROR, |
| 4479 | +(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), |
| 4480 | +errmsg("wrong range of array_subscripts"), |
| 4481 | +errhint("Lower bound of dimension array must be one."))); |
| 4482 | + |
| 4483 | +if (ARR_HASNULL(lbs)) |
| 4484 | +ereport(ERROR, |
| 4485 | +(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
| 4486 | +errmsg("dimension values cannot be null"))); |
| 4487 | + |
| 4488 | +if (ARR_DIMS(lbs)[0]!=ndims) |
| 4489 | +ereport(ERROR, |
| 4490 | + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), |
| 4491 | +errmsg("wrong number of array_subscripts"), |
| 4492 | +errhint("Low bound array has different size than dimensions array."))); |
| 4493 | + |
| 4494 | +lbsv= (int*)ARR_DATA_PTR(lbs); |
| 4495 | +} |
| 4496 | +else |
| 4497 | +{ |
| 4498 | +inti; |
| 4499 | + |
| 4500 | +for (i=0;i<MAXDIM;i++) |
| 4501 | +deflbs[i]=1; |
| 4502 | + |
| 4503 | +lbsv=deflbs; |
| 4504 | +} |
| 4505 | + |
| 4506 | +/* fast track for empty array */ |
| 4507 | +if (ndims==0) |
| 4508 | +returnconstruct_empty_array(elmtype); |
| 4509 | + |
| 4510 | +nitems=ArrayGetNItems(ndims,dimv); |
| 4511 | + |
| 4512 | + |
| 4513 | +/* |
| 4514 | + * We arrange to look up info about element type only once per series of |
| 4515 | + * calls, assuming the element type doesn't change underneath us. |
| 4516 | + */ |
| 4517 | +my_extra= (ArrayMetaState*)fcinfo->flinfo->fn_extra; |
| 4518 | +if (my_extra==NULL) |
| 4519 | +{ |
| 4520 | +fcinfo->flinfo->fn_extra=MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, |
| 4521 | +sizeof(ArrayMetaState)); |
| 4522 | +my_extra= (ArrayMetaState*)fcinfo->flinfo->fn_extra; |
| 4523 | +my_extra->element_type=InvalidOid; |
| 4524 | +} |
| 4525 | + |
| 4526 | +if (my_extra->element_type!=elmtype) |
| 4527 | +{ |
| 4528 | +/* Get info about element type */ |
| 4529 | +get_typlenbyvalalign(elmtype, |
| 4530 | +&my_extra->typlen, |
| 4531 | +&my_extra->typbyval, |
| 4532 | +&my_extra->typalign); |
| 4533 | +my_extra->element_type=elmtype; |
| 4534 | +} |
| 4535 | + |
| 4536 | +elmlen=my_extra->typlen; |
| 4537 | +elmbyval=my_extra->typbyval; |
| 4538 | +elmalign=my_extra->typalign; |
| 4539 | + |
| 4540 | +/* compute required space */ |
| 4541 | +if (!isnull) |
| 4542 | +{ |
| 4543 | +inti; |
| 4544 | +char*p; |
| 4545 | +intnbytes; |
| 4546 | +Datumaux_value=value; |
| 4547 | + |
| 4548 | +/* make sure data is not toasted */ |
| 4549 | +if (elmlen==-1) |
| 4550 | +value=PointerGetDatum(PG_DETOAST_DATUM(value)); |
| 4551 | + |
| 4552 | +nbytes=att_addlength_datum(0,elmlen,value); |
| 4553 | +nbytes=att_align_nominal(nbytes,elmalign); |
| 4554 | + |
| 4555 | +nbytes *=nitems; |
| 4556 | +/* check for overflow of total request */ |
| 4557 | +if (!AllocSizeIsValid(nbytes)) |
| 4558 | +ereport(ERROR, |
| 4559 | +(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
| 4560 | +errmsg("array size exceeds the maximum allowed (%d)", |
| 4561 | +(int)MaxAllocSize))); |
| 4562 | + |
| 4563 | +nbytes+=ARR_OVERHEAD_NONULLS(ndims); |
| 4564 | +result=create_array_envelope(ndims,dimv,lbsv,nbytes, |
| 4565 | +elmtype,0); |
| 4566 | +p=ARR_DATA_PTR(result); |
| 4567 | +for (i=0;i<nitems;i++) |
| 4568 | +p+=ArrayCastAndSet(value,elmlen,elmbyval,elmalign,p); |
| 4569 | + |
| 4570 | +/* cleaning up detoasted copies of datum */ |
| 4571 | +if (aux_value!=value) |
| 4572 | +pfree((Pointer)value); |
| 4573 | +} |
| 4574 | +else |
| 4575 | +{ |
| 4576 | +intnbytes; |
| 4577 | +intdataoffset; |
| 4578 | +bits8*bitmap; |
| 4579 | + |
| 4580 | +dataoffset=ARR_OVERHEAD_WITHNULLS(ndims,nitems); |
| 4581 | +nbytes=dataoffset; |
| 4582 | + |
| 4583 | +result=create_array_envelope(ndims,dimv,lbsv,nbytes, |
| 4584 | +elmtype,dataoffset); |
| 4585 | +bitmap=ARR_NULLBITMAP(result); |
| 4586 | +MemSet(bitmap,0, (nitems+7) /8); |
| 4587 | +} |
| 4588 | + |
| 4589 | +returnresult; |
| 4590 | +} |