aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/numeric.c
diff options
context:
space:
mode:
authorFujii Masao <fujii@postgresql.org>2014-11-11 21:44:46 +0900
committerFujii Masao <fujii@postgresql.org>2014-11-11 21:44:46 +0900
commit1871c892021055532344266d7429b63f76a892c2 (patch)
tree398b1e6ba2740383da88257bc2531d81ec33fe46 /src/backend/utils/adt/numeric.c
parenta1b395b6a26ae80cde17fdfd2def8d351872f399 (diff)
downloadpostgresql-1871c892021055532344266d7429b63f76a892c2.tar.gz
postgresql-1871c892021055532344266d7429b63f76a892c2.zip
Add generate_series(numeric, numeric).
Платон Малюгин Reviewed by Michael Paquier, Ali Akbar and Marti Raudsepp
Diffstat (limited to 'src/backend/utils/adt/numeric.c')
-rw-r--r--src/backend/utils/adt/numeric.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 9b3f5b94107..d61af920cda 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -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"
@@ -261,6 +262,18 @@ typedef struct 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().