|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.59 2003/12/01 21:52:37 momjian Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.60 2004/02/03 08:29:56 joe Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
|
34 | 34 | #include <ctype.h>
|
35 | 35 | #include <limits.h>
|
36 | 36 |
|
| 37 | +#include "funcapi.h" |
37 | 38 | #include "libpq/pqformat.h"
|
38 | 39 | #include "utils/builtins.h"
|
39 | 40 |
|
|
44 | 45 | #define SHRT_MIN (-0x8000)
|
45 | 46 | #endif
|
46 | 47 |
|
| 48 | +typedef struct |
| 49 | +{ |
| 50 | + int32 current; |
| 51 | + int32 finish; |
| 52 | + int32 step; |
| 53 | +} generate_series_fctx; |
| 54 | + |
47 | 55 | /*****************************************************************************
|
48 | 56 | * USER I/O ROUTINES *
|
49 | 57 | *****************************************************************************/
|
@@ -1021,3 +1029,84 @@ int2shr(PG_FUNCTION_ARGS)
|
1021 | 1029 |
|
1022 | 1030 | PG_RETURN_INT16(arg1 >> arg2);
|
1023 | 1031 | }
|
| 1032 | + |
| 1033 | +/* |
| 1034 | + * non-persistent numeric series generator |
| 1035 | + */ |
| 1036 | +Datum |
| 1037 | +generate_series_int4(PG_FUNCTION_ARGS) |
| 1038 | +{ |
| 1039 | + return generate_series_step_int4(fcinfo); |
| 1040 | +} |
| 1041 | + |
| 1042 | +Datum |
| 1043 | +generate_series_step_int4(PG_FUNCTION_ARGS) |
| 1044 | +{ |
| 1045 | + FuncCallContext *funcctx; |
| 1046 | + generate_series_fctx *fctx; |
| 1047 | + int32 result; |
| 1048 | + MemoryContext oldcontext; |
| 1049 | + |
| 1050 | + /* stuff done only on the first call of the function */ |
| 1051 | + if (SRF_IS_FIRSTCALL()) |
| 1052 | + { |
| 1053 | + int32 start = PG_GETARG_INT32(0); |
| 1054 | + int32 finish = PG_GETARG_INT32(1); |
| 1055 | + int32 step = 1; |
| 1056 | + |
| 1057 | + /* see if we were given an explicit step size */ |
| 1058 | + if (PG_NARGS() == 3) |
| 1059 | + step = PG_GETARG_INT32(2); |
| 1060 | + if (step == 0) |
| 1061 | + ereport(ERROR, |
| 1062 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 1063 | + errmsg("step size may not equal zero"))); |
| 1064 | + |
| 1065 | + /* create a function context for cross-call persistence */ |
| 1066 | + funcctx = SRF_FIRSTCALL_INIT(); |
| 1067 | + |
| 1068 | + /* |
| 1069 | + * switch to memory context appropriate for multiple function |
| 1070 | + * calls |
| 1071 | + */ |
| 1072 | + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); |
| 1073 | + |
| 1074 | + /* allocate memory for user context */ |
| 1075 | + fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx)); |
| 1076 | + |
| 1077 | + /* |
| 1078 | + * Use fctx to keep state from call to call. |
| 1079 | + * Seed current with the original start value |
| 1080 | + */ |
| 1081 | + fctx->current = start; |
| 1082 | + fctx->finish = finish; |
| 1083 | + fctx->step = step; |
| 1084 | + |
| 1085 | + funcctx->user_fctx = fctx; |
| 1086 | + MemoryContextSwitchTo(oldcontext); |
| 1087 | + } |
| 1088 | + |
| 1089 | + /* stuff done on every call of the function */ |
| 1090 | + funcctx = SRF_PERCALL_SETUP(); |
| 1091 | + |
| 1092 | + /* |
| 1093 | + * get the saved state and use current as the result for |
| 1094 | + * this iteration |
| 1095 | + */ |
| 1096 | + fctx = funcctx->user_fctx; |
| 1097 | + result = fctx->current; |
| 1098 | + |
| 1099 | + if ((fctx->step > 0 && fctx->current <= fctx->finish) || |
| 1100 | + (fctx->step < 0 && fctx->current >= fctx->finish)) |
| 1101 | + { |
| 1102 | + /* increment current in preparation for next iteration */ |
| 1103 | + fctx->current += fctx->step; |
| 1104 | + |
| 1105 | + /* do when there is more left to send */ |
| 1106 | + SRF_RETURN_NEXT(funcctx, Int32GetDatum(result)); |
| 1107 | + } |
| 1108 | + else |
| 1109 | + /* do when there is no more left */ |
| 1110 | + SRF_RETURN_DONE(funcctx); |
| 1111 | +} |
| 1112 | + |
0 commit comments