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:
@ -14076,8 +14076,8 @@ AND
|
|||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry><literal><function>generate_series(<parameter>start</parameter>, <parameter>stop</parameter>)</function></literal></entry>
|
<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>int</type>, <type>bigint</type> or <type>numeric</type></entry>
|
||||||
<entry><type>setof int</type> or <type>setof bigint</type> (same as argument type)</entry>
|
<entry><type>setof int</type>, <type>setof bigint</type>, or <type>setof numeric</type> (same as argument type)</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Generate a series of values, from <parameter>start</parameter> to <parameter>stop</parameter>
|
Generate a series of values, from <parameter>start</parameter> to <parameter>stop</parameter>
|
||||||
with a step size of one
|
with a step size of one
|
||||||
@ -14086,8 +14086,8 @@ AND
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><literal><function>generate_series(<parameter>start</parameter>, <parameter>stop</parameter>, <parameter>step</parameter>)</function></literal></entry>
|
<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>int</type>, <type>bigint</type> or <type>numeric</type></entry>
|
||||||
<entry><type>setof int</type> or <type>setof bigint</type> (same as argument type)</entry>
|
<entry><type>setof int</type>, <type>setof bigint</type> or <type>setof numeric</type> (same as argument type)</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Generate a series of values, from <parameter>start</parameter> to <parameter>stop</parameter>
|
Generate a series of values, from <parameter>start</parameter> to <parameter>stop</parameter>
|
||||||
with a step size of <parameter>step</parameter>
|
with a step size of <parameter>step</parameter>
|
||||||
@ -14137,6 +14137,14 @@ SELECT * FROM generate_series(4,3);
|
|||||||
-----------------
|
-----------------
|
||||||
(0 rows)
|
(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
|
-- 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);
|
SELECT current_date + s.a AS dates FROM generate_series(0,14,7) AS s(a);
|
||||||
dates
|
dates
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "access/hash.h"
|
#include "access/hash.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "funcapi.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
@ -260,6 +261,18 @@ typedef struct NumericVar
|
|||||||
} NumericVar;
|
} NumericVar;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* Data for generate_series
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
NumericVar current;
|
||||||
|
NumericVar stop;
|
||||||
|
NumericVar step;
|
||||||
|
} generate_series_numeric_fctx;
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Some preinitialized constants
|
* Some preinitialized constants
|
||||||
* ----------
|
* ----------
|
||||||
@ -1229,6 +1242,117 @@ numeric_floor(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_NUMERIC(res);
|
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
|
* Implements the numeric version of the width_bucket() function
|
||||||
* defined by SQL2003. See also width_bucket_float8().
|
* defined by SQL2003. See also width_bucket_float8().
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201411071
|
#define CATALOG_VERSION_NO 201411111
|
||||||
|
|
||||||
#endif
|
#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");
|
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_ ));
|
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");
|
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_ ));
|
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");
|
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_ ));
|
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 int2int4_sum(PG_FUNCTION_ARGS);
|
||||||
extern Datum width_bucket_numeric(PG_FUNCTION_ARGS);
|
extern Datum width_bucket_numeric(PG_FUNCTION_ARGS);
|
||||||
extern Datum hash_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 */
|
/* ri_triggers.c */
|
||||||
extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
|
extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
|
||||||
|
@ -1409,3 +1409,55 @@ select 10.0 ^ 2147483647 as overflows;
|
|||||||
ERROR: value overflows numeric format
|
ERROR: value overflows numeric format
|
||||||
select 117743296169.0 ^ 1000000000 as overflows;
|
select 117743296169.0 ^ 1000000000 as overflows;
|
||||||
ERROR: value overflows numeric format
|
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 rounds_to_zero;
|
||||||
select 10.0 ^ 2147483647 as overflows;
|
select 10.0 ^ 2147483647 as overflows;
|
||||||
select 117743296169.0 ^ 1000000000 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);
|
||||||
|
Reference in New Issue
Block a user