mirror of
https://github.com/postgres/postgres.git
synced 2025-06-03 00:02:26 -04:00
Add generate_series(numeric, numeric).
Платон Малюгин Reviewed by Michael Paquier, Ali Akbar and Marti Raudsepp
This commit is contained in:
parent
a1b395b6a2
commit
1871c89202
@ -14076,8 +14076,8 @@ AND
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal><function>generate_series(<parameter>start</parameter>, <parameter>stop</parameter>)</function></literal></entry>
|
||||
<entry><type>int</type> or <type>bigint</type></entry>
|
||||
<entry><type>setof int</type> or <type>setof bigint</type> (same as argument type)</entry>
|
||||
<entry><type>int</type>, <type>bigint</type> or <type>numeric</type></entry>
|
||||
<entry><type>setof int</type>, <type>setof bigint</type>, or <type>setof numeric</type> (same as argument type)</entry>
|
||||
<entry>
|
||||
Generate a series of values, from <parameter>start</parameter> to <parameter>stop</parameter>
|
||||
with a step size of one
|
||||
@ -14086,8 +14086,8 @@ AND
|
||||
|
||||
<row>
|
||||
<entry><literal><function>generate_series(<parameter>start</parameter>, <parameter>stop</parameter>, <parameter>step</parameter>)</function></literal></entry>
|
||||
<entry><type>int</type> or <type>bigint</type></entry>
|
||||
<entry><type>setof int</type> or <type>setof bigint</type> (same as argument type)</entry>
|
||||
<entry><type>int</type>, <type>bigint</type> or <type>numeric</type></entry>
|
||||
<entry><type>setof int</type>, <type>setof bigint</type> or <type>setof numeric</type> (same as argument type)</entry>
|
||||
<entry>
|
||||
Generate a series of values, from <parameter>start</parameter> to <parameter>stop</parameter>
|
||||
with a step size of <parameter>step</parameter>
|
||||
@ -14137,6 +14137,14 @@ SELECT * FROM generate_series(4,3);
|
||||
-----------------
|
||||
(0 rows)
|
||||
|
||||
SELECT generate_series(1.1, 4, 1.3);
|
||||
generate_series
|
||||
-----------------
|
||||
1.1
|
||||
2.4
|
||||
3.7
|
||||
(3 rows)
|
||||
|
||||
-- this example relies on the date-plus-integer operator
|
||||
SELECT current_date + s.a AS dates FROM generate_series(0,14,7) AS s(a);
|
||||
dates
|
||||
|
@ -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().
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201411071
|
||||
#define CATALOG_VERSION_NO 201411111
|
||||
|
||||
#endif
|
||||
|
@ -3952,6 +3952,10 @@ DATA(insert OID = 1068 ( generate_series PGNSP PGUID 12 1 1000 0 0 f f f f t t
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 1069 ( generate_series PGNSP PGUID 12 1 1000 0 0 f f f f t t i 2 0 20 "20 20" _null_ _null_ _null_ _null_ generate_series_int8 _null_ _null_ _null_ ));
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 3259 ( generate_series PGNSP PGUID 12 1 1000 0 0 f f f f t t i 3 0 1700 "1700 1700 1700" _null_ _null_ _null_ _null_ generate_series_step_numeric _null_ _null_ _null_ ));
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 3260 ( generate_series PGNSP PGUID 12 1 1000 0 0 f f f f t t i 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ generate_series_numeric _null_ _null_ _null_ ));
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 938 ( generate_series PGNSP PGUID 12 1 1000 0 0 f f f f t t i 3 0 1114 "1114 1114 1186" _null_ _null_ _null_ _null_ generate_series_timestamp _null_ _null_ _null_ ));
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 939 ( generate_series PGNSP PGUID 12 1 1000 0 0 f f f f t t s 3 0 1184 "1184 1184 1186" _null_ _null_ _null_ _null_ generate_series_timestamptz _null_ _null_ _null_ ));
|
||||
|
@ -1029,6 +1029,8 @@ extern Datum int8_avg(PG_FUNCTION_ARGS);
|
||||
extern Datum int2int4_sum(PG_FUNCTION_ARGS);
|
||||
extern Datum width_bucket_numeric(PG_FUNCTION_ARGS);
|
||||
extern Datum hash_numeric(PG_FUNCTION_ARGS);
|
||||
extern Datum generate_series_numeric(PG_FUNCTION_ARGS);
|
||||
extern Datum generate_series_step_numeric(PG_FUNCTION_ARGS);
|
||||
|
||||
/* ri_triggers.c */
|
||||
extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
|
||||
|
@ -1409,3 +1409,55 @@ select 10.0 ^ 2147483647 as overflows;
|
||||
ERROR: value overflows numeric format
|
||||
select 117743296169.0 ^ 1000000000 as overflows;
|
||||
ERROR: value overflows numeric format
|
||||
--
|
||||
-- Tests for generate_series
|
||||
--
|
||||
select * from generate_series(0.0::numeric, 4.0::numeric);
|
||||
generate_series
|
||||
-----------------
|
||||
0.0
|
||||
1.0
|
||||
2.0
|
||||
3.0
|
||||
4.0
|
||||
(5 rows)
|
||||
|
||||
select * from generate_series(0.1::numeric, 4.0::numeric, 1.3::numeric);
|
||||
generate_series
|
||||
-----------------
|
||||
0.1
|
||||
1.4
|
||||
2.7
|
||||
4.0
|
||||
(4 rows)
|
||||
|
||||
select * from generate_series(4.0::numeric, -1.5::numeric, -2.2::numeric);
|
||||
generate_series
|
||||
-----------------
|
||||
4.0
|
||||
1.8
|
||||
-0.4
|
||||
(3 rows)
|
||||
|
||||
-- Trigger errors
|
||||
select * from generate_series(-100::numeric, 100::numeric, 0::numeric);
|
||||
ERROR: step size cannot equal zero
|
||||
select * from generate_series(-100::numeric, 100::numeric, 'nan'::numeric);
|
||||
ERROR: step size cannot be NaN
|
||||
select * from generate_series('nan'::numeric, 100::numeric, 10::numeric);
|
||||
ERROR: start value cannot be NaN
|
||||
select * from generate_series(0::numeric, 'nan'::numeric, 10::numeric);
|
||||
ERROR: stop value cannot be NaN
|
||||
-- Checks maximum, output is truncated
|
||||
select (i / (10::numeric ^ 131071))::numeric(1,0)
|
||||
from generate_series(6 * (10::numeric ^ 131071),
|
||||
9 * (10::numeric ^ 131071),
|
||||
10::numeric ^ 131071) as a(i);
|
||||
numeric
|
||||
---------
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
(4 rows)
|
||||
|
||||
|
@ -837,3 +837,20 @@ select 10.0 ^ -2147483648 as rounds_to_zero;
|
||||
select 10.0 ^ -2147483647 as rounds_to_zero;
|
||||
select 10.0 ^ 2147483647 as overflows;
|
||||
select 117743296169.0 ^ 1000000000 as overflows;
|
||||
|
||||
--
|
||||
-- Tests for generate_series
|
||||
--
|
||||
select * from generate_series(0.0::numeric, 4.0::numeric);
|
||||
select * from generate_series(0.1::numeric, 4.0::numeric, 1.3::numeric);
|
||||
select * from generate_series(4.0::numeric, -1.5::numeric, -2.2::numeric);
|
||||
-- Trigger errors
|
||||
select * from generate_series(-100::numeric, 100::numeric, 0::numeric);
|
||||
select * from generate_series(-100::numeric, 100::numeric, 'nan'::numeric);
|
||||
select * from generate_series('nan'::numeric, 100::numeric, 10::numeric);
|
||||
select * from generate_series(0::numeric, 'nan'::numeric, 10::numeric);
|
||||
-- Checks maximum, output is truncated
|
||||
select (i / (10::numeric ^ 131071))::numeric(1,0)
|
||||
from generate_series(6 * (10::numeric ^ 131071),
|
||||
9 * (10::numeric ^ 131071),
|
||||
10::numeric ^ 131071) as a(i);
|
||||
|
Loading…
x
Reference in New Issue
Block a user