]> granicus.if.org Git - postgresql/commitdiff
Ensure variables live across calls in generate_series(numeric, numeric).
authorFujii Masao <fujii@postgresql.org>
Thu, 18 Dec 2014 12:13:52 +0000 (21:13 +0900)
committerFujii Masao <fujii@postgresql.org>
Thu, 18 Dec 2014 12:13:52 +0000 (21:13 +0900)
In generate_series_step_numeric(), the variables "start_num"
and "stop_num" may be potentially freed until the next call.
So they should be put in the location which can survive across calls.
But previously they were not, and which could cause incorrect
behavior of generate_series(numeric, numeric). This commit fixes
this problem by copying them on multi_call_memory_ctx.

Andrew Gierth

src/backend/utils/adt/numeric.c
src/test/regress/expected/numeric.out
src/test/regress/sql/numeric.sql

index c73f9bc005aece79b96b55faefee46fc359e4712..d841b6fa8b1d91efb7cdef0b3a7c2eb121ea2de4 100644 (file)
@@ -1325,11 +1325,16 @@ generate_series_step_numeric(PG_FUNCTION_ARGS)
 
                /*
                 * Use fctx to keep state from call to call. Seed current with the
-                * original start value.
+                * original start value. We must copy the start_num and stop_num
+                * values rather than pointing to them, since we may have detoasted
+                * them in the per-call context.
                 */
-               init_var_from_num(start_num, &fctx->current);
-               init_var_from_num(stop_num, &fctx->stop);
+               init_var(&fctx->current);
+               init_var(&fctx->stop);
                init_var(&fctx->step);
+
+               set_var_from_num(start_num, &fctx->current);
+               set_var_from_num(stop_num, &fctx->stop);
                set_var_from_var(&steploc, &fctx->step);
 
                funcctx->user_fctx = fctx;
index ee6cb50d5a60af688b2e1dc6c17dbce074af51fa..9d6814564df961c4dd4e6d449db3d32a9efe0894 100644 (file)
@@ -1461,3 +1461,41 @@ select (i / (10::numeric ^ 131071))::numeric(1,0)
        9
 (4 rows)
 
+-- Check usage with variables
+select * from generate_series(1::numeric, 3::numeric) i, generate_series(i,3) j;
+ i | j 
+---+---
+ 1 | 1
+ 1 | 2
+ 1 | 3
+ 2 | 2
+ 2 | 3
+ 3 | 3
+(6 rows)
+
+select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,i) j;
+ i | j 
+---+---
+ 1 | 1
+ 2 | 1
+ 2 | 2
+ 3 | 1
+ 3 | 2
+ 3 | 3
+(6 rows)
+
+select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,5,i) j;
+ i | j 
+---+---
+ 1 | 1
+ 1 | 2
+ 1 | 3
+ 1 | 4
+ 1 | 5
+ 2 | 1
+ 2 | 3
+ 2 | 5
+ 3 | 1
+ 3 | 4
+(10 rows)
+
index a7e92ac3ccf9dc080def867c49e7685af34c3b00..1633e4c375244f35b517d7a699b2a7c8ea7d3225 100644 (file)
@@ -854,3 +854,7 @@ 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);
+-- Check usage with variables
+select * from generate_series(1::numeric, 3::numeric) i, generate_series(i,3) j;
+select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,i) j;
+select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,5,i) j;