Commit f7399926 authored by Peter Eisentraut's avatar Peter Eisentraut

tablefunc: Reject negative number of tuples passed to normal_rand()

The function converted the first argument i.e. the number of tuples to
return into an unsigned integer which turns out to be huge number when
a negative value is passed.  This causes the function to take much
longer time to execute.  Instead, reject a negative value.

(If someone really wants to generate many more result rows, they
should consider adding a bigint or numeric variant.)

While at it, improve SQL test to test the number of tuples returned by
this function.

Author: Ashutosh Bapat <ashutosh.bapat@2ndquadrant.com>
Discussion: https://www.postgresql.org/message-id/CAG-ACPW3PUUmSnM6cLa9Rw4BEC5cEMKjX8Gogc8gvQcT3cYA1A@mail.gmail.com
parent 2fbd786c
...@@ -3,12 +3,15 @@ CREATE EXTENSION tablefunc; ...@@ -3,12 +3,15 @@ CREATE EXTENSION tablefunc;
-- normal_rand() -- normal_rand()
-- no easy way to do this for regression testing -- no easy way to do this for regression testing
-- --
SELECT avg(normal_rand)::int FROM normal_rand(100, 250, 0.2); SELECT avg(normal_rand)::int, count(*) FROM normal_rand(100, 250, 0.2);
avg avg | count
----- -----+-------
250 250 | 100
(1 row) (1 row)
-- negative number of tuples
SELECT avg(normal_rand)::int, count(*) FROM normal_rand(-1, 250, 0.2);
ERROR: number of rows cannot be negative
-- --
-- crosstab() -- crosstab()
-- --
......
...@@ -4,7 +4,9 @@ CREATE EXTENSION tablefunc; ...@@ -4,7 +4,9 @@ CREATE EXTENSION tablefunc;
-- normal_rand() -- normal_rand()
-- no easy way to do this for regression testing -- no easy way to do this for regression testing
-- --
SELECT avg(normal_rand)::int FROM normal_rand(100, 250, 0.2); SELECT avg(normal_rand)::int, count(*) FROM normal_rand(100, 250, 0.2);
-- negative number of tuples
SELECT avg(normal_rand)::int, count(*) FROM normal_rand(-1, 250, 0.2);
-- --
-- crosstab() -- crosstab()
......
...@@ -184,6 +184,8 @@ normal_rand(PG_FUNCTION_ARGS) ...@@ -184,6 +184,8 @@ normal_rand(PG_FUNCTION_ARGS)
/* stuff done only on the first call of the function */ /* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
{ {
int32 num_tuples;
/* create a function context for cross-call persistence */ /* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
...@@ -193,7 +195,12 @@ normal_rand(PG_FUNCTION_ARGS) ...@@ -193,7 +195,12 @@ normal_rand(PG_FUNCTION_ARGS)
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* total number of tuples to be returned */ /* total number of tuples to be returned */
funcctx->max_calls = PG_GETARG_UINT32(0); num_tuples = PG_GETARG_INT32(0);
if (num_tuples < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("number of rows cannot be negative")));
funcctx->max_calls = num_tuples;
/* allocate memory for user context */ /* allocate memory for user context */
fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx)); fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment