|
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 | int typlen, bool typbyval, char typalign);
|
97 | 97 | static int array_cmp(FunctionCallInfo fcinfo);
|
| 98 | +static ArrayType *create_array_envelope(int ndims, int *dimv, int *lbv, int nbytes, |
| 99 | + Oid elmtype, int dataoffset); |
| 100 | +static ArrayType *array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value, |
| 101 | + Oid elmtype, bool isnull, |
| 102 | + FunctionCallInfo fcinfo); |
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 | return generate_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 | + Oid elmtype; |
| 4334 | + Datum value; |
| 4335 | + bool isnull; |
| 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 | + Oid elmtype; |
| 4374 | + Datum value; |
| 4375 | + bool isnull; |
| 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 | +static ArrayType * |
| 4404 | +create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes, |
| 4405 | + Oid elmtype, int dataoffset) |
| 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 | + return result; |
| 4418 | +} |
| 4419 | + |
| 4420 | +static ArrayType * |
| 4421 | +array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value, |
| 4422 | + Oid elmtype, bool isnull, |
| 4423 | + FunctionCallInfo fcinfo) |
| 4424 | +{ |
| 4425 | + ArrayType *result; |
| 4426 | + int *dimv; |
| 4427 | + int *lbsv; |
| 4428 | + int ndims; |
| 4429 | + int nitems; |
| 4430 | + int deflbs[MAXDIM]; |
| 4431 | + int16 elmlen; |
| 4432 | + bool elmbyval; |
| 4433 | + char elmalign; |
| 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 | + int i; |
| 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 | + return construct_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 | + int i; |
| 4544 | + char *p; |
| 4545 | + int nbytes; |
| 4546 | + Datum aux_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 | + int nbytes; |
| 4577 | + int dataoffset; |
| 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 | + return result; |
| 4590 | +} |
0 commit comments