Skip to content

Commit dd3e830

Browse files
committed
add Integer generate series
1 parent fad986a commit dd3e830

File tree

4 files changed

+150
-5
lines changed

4 files changed

+150
-5
lines changed

regress/expected/cypher_with.out

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ USE GRAPH cypher_with;
3333

3434
(1 row)
3535

36-
WITH true AS b RETURN b;
37-
ERROR: syntax error at or near "true"
38-
LINE 1: WITH true AS b RETURN b;
39-
^
36+
CYPHER WITH true AS b RETURN b;
37+
b
38+
------
39+
true
40+
(1 row)
41+
4042
CREATE ({i: 1}), ({i: 1, j: 2}), ({i: 2});
4143
--
4244
(0 rows)
@@ -54,6 +56,31 @@ MATCH (n) WITH n as a WHERE n.i = 1 and n.j = 2 RETURN a;
5456
{"id": 281474976710658, "label": "", "properties": {"i": 1, "j": 2}}
5557
(1 row)
5658

59+
CYPHER WITH generate_series(1, 10) as i RETURN i;
60+
i
61+
----
62+
1
63+
2
64+
3
65+
4
66+
5
67+
6
68+
7
69+
8
70+
9
71+
10
72+
(10 rows)
73+
74+
CYPHER WITH generate_series(1, 10, 2) as i RETURN i;
75+
i
76+
---
77+
1
78+
3
79+
5
80+
7
81+
9
82+
(5 rows)
83+
5784
--Error
5885
WITH 1 + 1 RETURN i;
5986
ERROR: syntax error at or near "1"

regress/sql/cypher_with.sql

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@ SET search_path TO postgraph;
2424
CREATE GRAPH cypher_with;
2525
USE GRAPH cypher_with;
2626

27-
WITH true AS b RETURN b;
27+
CYPHER WITH true AS b RETURN b;
2828

2929
CREATE ({i: 1}), ({i: 1, j: 2}), ({i: 2});
3030

3131
MATCH (n) WITH n as a WHERE n.i = 1 RETURN a;
3232

3333
MATCH (n) WITH n as a WHERE n.i = 1 and n.j = 2 RETURN a;
3434

35+
36+
CYPHER WITH generate_series(1, 10) as i RETURN i;
37+
38+
CYPHER WITH generate_series(1, 10, 2) as i RETURN i;
39+
3540
--Error
3641
WITH 1 + 1 RETURN i;
3742

sql/postgraph-gtype.sql.in

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,18 @@ AS
571571
FUNCTION 4 gin_consistent_gtype,
572572
FUNCTION 6 gin_triconsistent_gtype,
573573
STORAGE text;
574+
575+
CREATE FUNCTION generate_series (gtype, gtype)
576+
RETURNS SETOF gtype
577+
LANGUAGE c
578+
IMMUTABLE
579+
PARALLEL SAFE
580+
AS 'MODULE_PATHNAME', 'generate_series_gtype';
581+
582+
583+
CREATE FUNCTION generate_series (gtype, gtype, gtype)
584+
RETURNS SETOF gtype
585+
LANGUAGE c
586+
IMMUTABLE
587+
PARALLEL SAFE
588+
AS 'MODULE_PATHNAME', 'generate_series_step_gtype';

src/backend/utils/adt/gtype.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,3 +2986,101 @@ Datum gtype_unnest(PG_FUNCTION_ARGS)
29862986

29872987
PG_RETURN_NULL();
29882988
}
2989+
2990+
2991+
#include "common/int.h"
2992+
2993+
typedef struct
2994+
{
2995+
int64 current;
2996+
int64 finish;
2997+
int64 step;
2998+
} generate_series_fctx;
2999+
3000+
PG_FUNCTION_INFO_V1(generate_series_gtype);
3001+
PG_FUNCTION_INFO_V1(generate_series_step_gtype);
3002+
3003+
/*
3004+
* non-persistent numeric series generator
3005+
*/
3006+
Datum
3007+
generate_series_gtype(PG_FUNCTION_ARGS)
3008+
{
3009+
return generate_series_step_gtype(fcinfo);
3010+
}
3011+
3012+
Datum
3013+
generate_series_step_gtype(PG_FUNCTION_ARGS)
3014+
{
3015+
FuncCallContext *funcctx;
3016+
generate_series_fctx *fctx;
3017+
int64 result;
3018+
MemoryContext oldcontext;
3019+
3020+
/* stuff done only on the first call of the function */
3021+
if (SRF_IS_FIRSTCALL())
3022+
{
3023+
int64 start = DatumGetInt64(convert_to_scalar(gtype_to_int8_internal, AG_GET_ARG_GTYPE_P(0), "int"));
3024+
int64 finish = DatumGetInt64(convert_to_scalar(gtype_to_int8_internal, AG_GET_ARG_GTYPE_P(1), "int"));
3025+
int64 step = 1;
3026+
3027+
/* see if we were given an explicit step size */
3028+
if (PG_NARGS() == 3)
3029+
step = DatumGetInt64(convert_to_scalar(gtype_to_int8_internal, AG_GET_ARG_GTYPE_P(2), "int"));
3030+
if (step == 0)
3031+
ereport(ERROR,
3032+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3033+
errmsg("step size cannot equal zero")));
3034+
3035+
/* create a function context for cross-call persistence */
3036+
funcctx = SRF_FIRSTCALL_INIT();
3037+
3038+
/*
3039+
* switch to memory context appropriate for multiple function calls
3040+
*/
3041+
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
3042+
3043+
/* allocate memory for user context */
3044+
fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx));
3045+
3046+
/*
3047+
* Use fctx to keep state from call to call. Seed current with the
3048+
* original start value
3049+
*/
3050+
fctx->current = start;
3051+
fctx->finish = finish;
3052+
fctx->step = step;
3053+
3054+
funcctx->user_fctx = fctx;
3055+
MemoryContextSwitchTo(oldcontext);
3056+
}
3057+
3058+
/* stuff done on every call of the function */
3059+
funcctx = SRF_PERCALL_SETUP();
3060+
3061+
/*
3062+
* get the saved state and use current as the result for this iteration
3063+
*/
3064+
fctx = funcctx->user_fctx;
3065+
result = fctx->current;
3066+
3067+
if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
3068+
(fctx->step < 0 && fctx->current >= fctx->finish))
3069+
{
3070+
/*
3071+
* Increment current in preparation for next iteration. If next-value
3072+
* computation overflows, this is the final result.
3073+
*/
3074+
if (pg_add_s64_overflow(fctx->current, fctx->step, &fctx->current))
3075+
fctx->step = 0;
3076+
3077+
gtype_value gtv = { .type = AGTV_INTEGER, .val.int_value = result };
3078+
3079+
3080+
/* do when there is more left to send */
3081+
SRF_RETURN_NEXT(funcctx, GTYPE_P_GET_DATUM(gtype_value_to_gtype(&gtv)));
3082+
}
3083+
else
3084+
/* do when there is no more left */
3085+
SRF_RETURN_DONE(funcctx);
3086+
}

0 commit comments

Comments
 (0)