mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Add generate_series(numeric, numeric).
Платон Малюгин Reviewed by Michael Paquier, Ali Akbar and Marti Raudsepp
This commit is contained in:
@ -28,6 +28,7 @@
|
||||
|
||||
#include "access/hash.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "funcapi.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
@ -260,6 +261,18 @@ typedef struct NumericVar
|
||||
} NumericVar;
|
||||
|
||||
|
||||
/* ----------
|
||||
* Data for generate_series
|
||||
* ----------
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
NumericVar current;
|
||||
NumericVar stop;
|
||||
NumericVar step;
|
||||
} generate_series_numeric_fctx;
|
||||
|
||||
|
||||
/* ----------
|
||||
* Some preinitialized constants
|
||||
* ----------
|
||||
@ -1229,6 +1242,117 @@ numeric_floor(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_NUMERIC(res);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* generate_series_numeric() -
|
||||
*
|
||||
* Generate series of numeric.
|
||||
*/
|
||||
Datum
|
||||
generate_series_numeric(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return generate_series_step_numeric(fcinfo);
|
||||
}
|
||||
|
||||
Datum
|
||||
generate_series_step_numeric(PG_FUNCTION_ARGS)
|
||||
{
|
||||
generate_series_numeric_fctx *fctx;
|
||||
FuncCallContext *funcctx;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
Numeric start_num = PG_GETARG_NUMERIC(0);
|
||||
Numeric stop_num = PG_GETARG_NUMERIC(1);
|
||||
NumericVar steploc = const_one;
|
||||
|
||||
/* handle NaN in start and stop values */
|
||||
if (NUMERIC_IS_NAN(start_num))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("start value cannot be NaN")));
|
||||
|
||||
if (NUMERIC_IS_NAN(stop_num))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("stop value cannot be NaN")));
|
||||
|
||||
/* see if we were given an explicit step size */
|
||||
if (PG_NARGS() == 3)
|
||||
{
|
||||
Numeric step_num = PG_GETARG_NUMERIC(2);
|
||||
|
||||
if (NUMERIC_IS_NAN(step_num))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("step size cannot be NaN")));
|
||||
|
||||
init_var_from_num(step_num, &steploc);
|
||||
|
||||
if (cmp_var(&steploc, &const_zero) == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("step size cannot equal zero")));
|
||||
}
|
||||
|
||||
/* create a function context for cross-call persistence */
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
|
||||
/*
|
||||
* Switch to memory context appropriate for multiple function calls.
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
/* allocate memory for user context */
|
||||
fctx = (generate_series_numeric_fctx *)
|
||||
palloc(sizeof(generate_series_numeric_fctx));
|
||||
|
||||
/*
|
||||
* Use fctx to keep state from call to call. Seed current with the
|
||||
* original start value.
|
||||
*/
|
||||
init_var_from_num(start_num, &fctx->current);
|
||||
init_var_from_num(stop_num, &fctx->stop);
|
||||
init_var(&fctx->step);
|
||||
set_var_from_var(&steploc, &fctx->step);
|
||||
|
||||
funcctx->user_fctx = fctx;
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/* stuff done on every call of the function */
|
||||
funcctx = SRF_PERCALL_SETUP();
|
||||
|
||||
/*
|
||||
* Get the saved state and use current state as the result of this
|
||||
* iteration.
|
||||
*/
|
||||
fctx = funcctx->user_fctx;
|
||||
|
||||
if ((fctx->step.sign == NUMERIC_POS &&
|
||||
cmp_var(&fctx->current, &fctx->stop) <= 0) ||
|
||||
(fctx->step.sign == NUMERIC_NEG &&
|
||||
cmp_var(&fctx->current, &fctx->stop) >= 0))
|
||||
{
|
||||
Numeric result = make_result(&fctx->current);
|
||||
|
||||
/* switch to memory context appropriate for iteration calculation */
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
/* increment current in preparation for next iteration */
|
||||
add_var(&fctx->current, &fctx->step, &fctx->current);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
/* do when there is more left to send */
|
||||
SRF_RETURN_NEXT(funcctx, NumericGetDatum(result));
|
||||
}
|
||||
else
|
||||
/* do when there is no more left */
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implements the numeric version of the width_bucket() function
|
||||
* defined by SQL2003. See also width_bucket_float8().
|
||||
|
Reference in New Issue
Block a user