On Tue, Sep 30, 2014 at 10:00 AM, Michael Paquier <michael.paqu...@gmail.com
> wrote:

>
>
> On Mon, Sep 29, 2014 at 4:19 PM, Michael Paquier <
> michael.paqu...@gmail.com> wrote:
>
>>
>> Michael
>> Btw, while looking at your patch, I actually hacked it a bit and finished
>> with the attached:
>> - changed process to use NumericVar instead of Numeric
>> - addition of custom step values with a function
>> generate_series(numeric,numeric,numeric)
>> - some cleanup and some comments here and there
>> That's still WIP, but feel free to use it for future work. If you are
>> able to add documentation and regression tests to this patch, I would
>> recommend that you register it to the next commit fest, where it would get
>> more review, and hopefully it will get committed.
>>
> Oops, it seems that I have been too hasty here. With a fresh mind I looked
> at my own patch again and found two bugs:
> - Incorrect initialization of step variable with const_one
> - Incorrect calculation of each step's value, making stuff crash, it is
> necessary to switch to the context of the function to perform operations on
> a temporary variable first.
>
And here is the patch...
-- 
Michael
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 2d6a4cb..4c2ff5b 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -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,13 @@ typedef struct NumericVar
 } NumericVar;
 
 
+typedef struct
+{
+	NumericVar current;
+	NumericVar finish;
+	NumericVar step;
+} generate_series_numeric_fctx;
+
 /* ----------
  * Some preinitialized constants
  * ----------
@@ -1221,6 +1229,108 @@ numeric_floor(PG_FUNCTION_ARGS)
 	PG_RETURN_NUMERIC(res);
 }
 
+
+/*
+ * generate_series_numeric() -
+ *
+ *  Generate series of numeric.
+ */
+Datum
+generate_series_numeric(PG_FUNCTION_ARGS)
+{
+	generate_series_numeric_fctx *fctx;
+	FuncCallContext *funcctx;
+	Numeric res;
+
+	if (SRF_IS_FIRSTCALL())
+	{
+		Numeric start_num  = PG_GETARG_NUMERIC(0);
+		Numeric finish_num = PG_GETARG_NUMERIC(1);
+		NumericVar steploc;
+		MemoryContext oldcontext;
+
+		/* see if we were given an explicit step size */
+		if (PG_NARGS() == 3)
+		{
+			Numeric step_num;
+			step_num = PG_GETARG_NUMERIC(2);
+
+			/* Transform step into a variable that can be manipulated */
+			init_var_from_num(step_num, &steploc);
+		}
+		else
+		{
+			init_var(&steploc);
+			set_var_from_var(&const_one, &steploc);
+		}
+
+		/* Step cannot be zero */
+		if (cmp_var(&steploc, &const_zero) == 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("step size cannot equal zero")));
+
+		/*
+		 * switch to memory context appropriate for multiple function calls
+		 */
+		funcctx = SRF_FIRSTCALL_INIT();
+
+		/* allocate memory for user context */
+		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(finish_num, &(fctx->finish));
+		init_var(&(fctx->step));
+		set_var_from_var(&steploc, &(fctx->step));
+		funcctx->user_fctx = fctx;
+		free_var(&steploc);
+		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;
+	res = make_result(&(fctx->current));
+
+	if ((cmp_var(&(fctx->step), &const_zero) > 0 &&
+		 cmp_var(&(fctx->current), &(fctx->finish)) <= 0) ||
+		(cmp_var(&(fctx->step), &const_zero) < 0 &&
+		 cmp_var(&(fctx->current), &(fctx->finish)) >= 0))
+	{
+		NumericVar tmp;
+		MemoryContext oldcontext;
+
+		/*
+		 * Increment for next iteration and perform operation in the context
+		 * of this function. Switch back to memory context of function before
+		 * performing any operations.
+		 */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+		init_var(&tmp);
+		add_var(&(fctx->current), &(fctx->step), &tmp);
+		set_var_from_var(&tmp, &(fctx->current));
+		free_var(&tmp);
+		MemoryContextSwitchTo(oldcontext);
+		SRF_RETURN_NEXT(funcctx, NumericGetDatum(res));
+	}
+	else
+	{
+		SRF_RETURN_DONE(funcctx);
+	}
+}
+
 /*
  * Implements the numeric version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_float8().
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 3ce9849..ccdf3e8 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3923,6 +3923,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 = 6000 (  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_numeric _null_ _null_ _null_ ));
+DESCR("non-persistent series generator");
+DATA(insert OID = 6001 (  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_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index d88e7a3..511518d 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -1040,6 +1040,7 @@ 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);
 
 /* ri_triggers.c */
 extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to