Add timestamp and timestamptz versions of generate_series().
Hitoshi Harada
This commit is contained in:
parent
600da67fbe
commit
b6d15590f7
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.435 2008/05/04 21:13:35 tgl Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.436 2008/05/04 23:19:23 tgl Exp $ -->
|
||||
|
||||
<chapter id="functions">
|
||||
<title>Functions and Operators</title>
|
||||
@ -10650,6 +10650,16 @@ AND
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal><function>generate_series</function>(<parameter>start</parameter>, <parameter>stop</parameter>, <parameter>step</parameter> <type>interval</>)</literal></entry>
|
||||
<entry><type>timestamp</type> or <type>timestamp with time zone</type></entry>
|
||||
<entry><type>setof timestamp</type> or <type>setof timestamp with time zone</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>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@ -10683,6 +10693,7 @@ select * from generate_series(4,3);
|
||||
-----------------
|
||||
(0 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
|
||||
------------
|
||||
@ -10690,16 +10701,26 @@ select current_date + s.a as dates from generate_series(0,14,7) as s(a);
|
||||
2004-02-12
|
||||
2004-02-19
|
||||
(3 rows)
|
||||
|
||||
select * from generate_series('2008-03-01 00:00'::timestamp,
|
||||
'2008-03-04 12:00', '10 hours');
|
||||
generate_series
|
||||
---------------------
|
||||
2008-03-01 00:00:00
|
||||
2008-03-01 10:00:00
|
||||
2008-03-01 20:00:00
|
||||
2008-03-02 06:00:00
|
||||
2008-03-02 16:00:00
|
||||
2008-03-03 02:00:00
|
||||
2008-03-03 12:00:00
|
||||
2008-03-03 22:00:00
|
||||
2008-03-04 08:00:00
|
||||
(9 rows)
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<table id="functions-srf-subscripts">
|
||||
|
||||
<indexterm>
|
||||
<primary>generate_subscripts</primary>
|
||||
</indexterm>
|
||||
|
||||
<title>Subscripts Generating Functions</title>
|
||||
<title>Subscript Generating Functions</title>
|
||||
<tgroup cols="3">
|
||||
<thead>
|
||||
<row>
|
||||
@ -10711,7 +10732,7 @@ select current_date + s.a as dates from generate_series(0,14,7) as s(a);
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal><function>generate_subscripts</function>(<parameter>array annyarray</parameter>, <parameter>dim int</parameter>)</literal></entry>
|
||||
<entry><literal><function>generate_subscripts</function>(<parameter>array anyarray</parameter>, <parameter>dim int</parameter>)</literal></entry>
|
||||
<entry><type>setof int</type></entry>
|
||||
<entry>
|
||||
Generate a series comprising the given array's subscripts.
|
||||
@ -10719,7 +10740,7 @@ select current_date + s.a as dates from generate_series(0,14,7) as s(a);
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal><function>generate_subscripts</function>(<parameter>array annyarray</parameter>, <parameter>dim int</parameter>, <parameter>reverse boolean</parameter>)</literal></entry>
|
||||
<entry><literal><function>generate_subscripts</function>(<parameter>array anyarray</parameter>, <parameter>dim int</parameter>, <parameter>reverse boolean</parameter>)</literal></entry>
|
||||
<entry><type>setof int</type></entry>
|
||||
<entry>
|
||||
Generate a series comprising the given array's subscripts. When
|
||||
@ -10732,10 +10753,17 @@ select current_date + s.a as dates from generate_series(0,14,7) as s(a);
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<indexterm>
|
||||
<primary>generate_subscripts</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
<function>generate_subscripts</> is a convenience function that generates
|
||||
the set of valid subscripts for the specified dimension of the given
|
||||
array.
|
||||
Zero rows are returned for arrays that do not have the requested dimension,
|
||||
or for NULL arrays (but valid subscripts are returned for NULL array
|
||||
elements.) Some examples follow:
|
||||
elements). Some examples follow:
|
||||
<programlisting>
|
||||
-- basic usage
|
||||
select generate_subscripts('{NULL,1,NULL,2}'::int[], 1) as s;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.188 2008/05/04 21:13:35 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.189 2008/05/04 23:19:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -24,6 +24,7 @@
|
||||
#include "access/hash.h"
|
||||
#include "access/xact.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "funcapi.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/scansup.h"
|
||||
@ -45,6 +46,22 @@ TimestampTz PgStartTime;
|
||||
/* Set at configuration reload */
|
||||
TimestampTz PgReloadTime;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Timestamp current;
|
||||
Timestamp finish;
|
||||
Interval step;
|
||||
int step_sign;
|
||||
} generate_series_timestamp_fctx;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TimestampTz current;
|
||||
TimestampTz finish;
|
||||
Interval step;
|
||||
int step_sign;
|
||||
} generate_series_timestamptz_fctx;
|
||||
|
||||
|
||||
static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
|
||||
static int EncodeSpecialTimestamp(Timestamp dt, char *str);
|
||||
@ -4651,3 +4668,165 @@ timestamptz_izone(PG_FUNCTION_ARGS)
|
||||
|
||||
PG_RETURN_TIMESTAMP(result);
|
||||
}
|
||||
|
||||
/* generate_series_timestamp()
|
||||
* Generate the set of timestamps from start to finish by step
|
||||
*/
|
||||
Datum
|
||||
generate_series_timestamp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
generate_series_timestamp_fctx *fctx;
|
||||
Timestamp result;
|
||||
|
||||
/* stuff done only on the first call of the function */
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
Timestamp start = PG_GETARG_TIMESTAMP(0);
|
||||
Timestamp finish = PG_GETARG_TIMESTAMP(1);
|
||||
Interval *step = PG_GETARG_INTERVAL_P(2);
|
||||
MemoryContext oldcontext;
|
||||
Interval interval_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_timestamp_fctx *)
|
||||
palloc(sizeof(generate_series_timestamp_fctx));
|
||||
|
||||
/*
|
||||
* Use fctx to keep state from call to call. Seed current with the
|
||||
* original start value
|
||||
*/
|
||||
fctx->current = start;
|
||||
fctx->finish = finish;
|
||||
fctx->step = *step;
|
||||
|
||||
/* Determine sign of the interval */
|
||||
MemSet(&interval_zero, 0, sizeof(Interval));
|
||||
fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
|
||||
|
||||
if (fctx->step_sign == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("step size cannot equal zero")));
|
||||
|
||||
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 as the result for this iteration
|
||||
*/
|
||||
fctx = funcctx->user_fctx;
|
||||
result = fctx->current;
|
||||
|
||||
if (fctx->step_sign > 0 ?
|
||||
timestamp_cmp_internal(result, fctx->finish) <= 0 :
|
||||
timestamp_cmp_internal(result, fctx->finish) >= 0)
|
||||
{
|
||||
/* increment current in preparation for next iteration */
|
||||
fctx->current = DatumGetTimestamp(
|
||||
DirectFunctionCall2(timestamp_pl_interval,
|
||||
TimestampGetDatum(fctx->current),
|
||||
PointerGetDatum(&fctx->step)));
|
||||
|
||||
/* do when there is more left to send */
|
||||
SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* do when there is no more left */
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate_series_timestamptz()
|
||||
* Generate the set of timestamps from start to finish by step
|
||||
*/
|
||||
Datum
|
||||
generate_series_timestamptz(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
generate_series_timestamptz_fctx *fctx;
|
||||
TimestampTz result;
|
||||
|
||||
/* stuff done only on the first call of the function */
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
|
||||
TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
|
||||
Interval *step = PG_GETARG_INTERVAL_P(2);
|
||||
MemoryContext oldcontext;
|
||||
Interval interval_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_timestamptz_fctx *)
|
||||
palloc(sizeof(generate_series_timestamptz_fctx));
|
||||
|
||||
/*
|
||||
* Use fctx to keep state from call to call. Seed current with the
|
||||
* original start value
|
||||
*/
|
||||
fctx->current = start;
|
||||
fctx->finish = finish;
|
||||
fctx->step = *step;
|
||||
|
||||
/* Determine sign of the interval */
|
||||
MemSet(&interval_zero, 0, sizeof(Interval));
|
||||
fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
|
||||
|
||||
if (fctx->step_sign == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("step size cannot equal zero")));
|
||||
|
||||
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 as the result for this iteration
|
||||
*/
|
||||
fctx = funcctx->user_fctx;
|
||||
result = fctx->current;
|
||||
|
||||
if (fctx->step_sign > 0 ?
|
||||
timestamp_cmp_internal(result, fctx->finish) <= 0 :
|
||||
timestamp_cmp_internal(result, fctx->finish) >= 0)
|
||||
{
|
||||
/* increment current in preparation for next iteration */
|
||||
fctx->current = DatumGetTimestampTz(
|
||||
DirectFunctionCall2(timestamptz_pl_interval,
|
||||
TimestampTzGetDatum(fctx->current),
|
||||
PointerGetDatum(&fctx->step)));
|
||||
|
||||
/* do when there is more left to send */
|
||||
SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* do when there is no more left */
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.454 2008/05/04 21:13:35 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.455 2008/05/04 23:19:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200805041
|
||||
#define CATALOG_VERSION_NO 200805042
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.495 2008/05/04 21:13:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.496 2008/05/04 23:19:23 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
@ -3872,6 +3872,10 @@ DATA(insert OID = 1068 ( generate_series PGNSP PGUID 12 1 1000 f f t t i 3 20 "
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 1069 ( generate_series PGNSP PGUID 12 1 1000 f f t t i 2 20 "20 20" _null_ _null_ _null_ generate_series_int8 - _null_ _null_ ));
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 938 ( generate_series PGNSP PGUID 12 1 1000 f f t t i 3 1114 "1114 1114 1186" _null_ _null_ _null_ generate_series_timestamp - _null_ _null_ ));
|
||||
DESCR("non-persistent series generator");
|
||||
DATA(insert OID = 939 ( generate_series PGNSP PGUID 12 1 1000 f f t t s 3 1184 "1184 1184 1186" _null_ _null_ _null_ generate_series_timestamptz - _null_ _null_ ));
|
||||
DESCR("non-persistent series generator");
|
||||
|
||||
/* boolean aggregates */
|
||||
DATA(insert OID = 2515 ( booland_statefunc PGNSP PGUID 12 1 0 f f t f i 2 16 "16 16" _null_ _null_ _null_ booland_statefunc - _null_ _null_ ));
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.77 2008/05/04 21:13:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.78 2008/05/04 23:19:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -308,6 +308,9 @@ extern Datum clock_timestamp(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_postmaster_start_time(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_conf_load_time(PG_FUNCTION_ARGS);
|
||||
|
||||
extern Datum generate_series_timestamp(PG_FUNCTION_ARGS);
|
||||
extern Datum generate_series_timestamptz(PG_FUNCTION_ARGS);
|
||||
|
||||
/* Internal routines (not fmgr-callable) */
|
||||
|
||||
extern TimestampTz GetCurrentTimestamp(void);
|
||||
|
Loading…
Reference in New Issue
Block a user