Skip to content

Commit

Permalink
Check if the limit is null (#7665)
Browse files Browse the repository at this point in the history
DESCRIPTION: Add a check to see if the given limit is null. 

Fixes a bug by checking if the limit given in the query is null when the
actual limit is computed with respect to the given offset.
Prior to this change, null is interpreted as 0 during the limit
calculation when both limit and offset are given.

Fixes #7663
  • Loading branch information
eaydingol authored Jul 31, 2024
1 parent 2a263fe commit 9e1852e
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 8 deletions.
29 changes: 21 additions & 8 deletions src/backend/distributed/planner/multi_logical_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4753,22 +4753,35 @@ WorkerLimitCount(Node *limitCount, Node *limitOffset, OrderByLimitReference
if (workerLimitNode != NULL && limitOffset != NULL)
{
Const *workerLimitConst = (Const *) workerLimitNode;
Const *workerOffsetConst = (Const *) limitOffset;
int64 workerLimitCount = DatumGetInt64(workerLimitConst->constvalue);
int64 workerOffsetCount = DatumGetInt64(workerOffsetConst->constvalue);

workerLimitCount = workerLimitCount + workerOffsetCount;
workerLimitNode = (Node *) MakeIntegerConstInt64(workerLimitCount);
/* Only update the worker limit if the const is not null.*/
if (!workerLimitConst->constisnull)
{
Const *workerOffsetConst = (Const *) limitOffset;
int64 workerLimitCount = DatumGetInt64(workerLimitConst->constvalue);

/* If the offset is null, it defaults to 0 when cast to int64. */
int64 workerOffsetCount = DatumGetInt64(workerOffsetConst->constvalue);
workerLimitCount = workerLimitCount + workerOffsetCount;
workerLimitNode = (Node *) MakeIntegerConstInt64(workerLimitCount);
}
}

/* display debug message on limit push down */
if (workerLimitNode != NULL)
{
Const *workerLimitConst = (Const *) workerLimitNode;
int64 workerLimitCount = DatumGetInt64(workerLimitConst->constvalue);
if (!workerLimitConst->constisnull)
{
int64 workerLimitCount = DatumGetInt64(workerLimitConst->constvalue);

ereport(DEBUG1, (errmsg("push down of limit count: " INT64_FORMAT,
workerLimitCount)));
ereport(DEBUG1, (errmsg("push down of limit count: " INT64_FORMAT,
workerLimitCount)));
}
else
{
ereport(DEBUG1, (errmsg("push down of limit count: ALL")));
}
}

return workerLimitNode;
Expand Down
80 changes: 80 additions & 0 deletions src/test/regress/expected/multi_limit_clause.out
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,86 @@ SELECT
1 | 1
(1 row)

-- check if we can correctly push the limit when it is null
SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey LIMIT null;
DEBUG: push down of limit count: ALL
l_orderkey
---------------------------------------------------------------------
1
1
1
1
1
1
2
(7 rows)

SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey OFFSET 1 LIMIT null;
DEBUG: push down of limit count: ALL
l_orderkey
---------------------------------------------------------------------
1
1
1
1
1
2
(6 rows)

SELECT count(*) FROM lineitem LIMIT null;
DEBUG: push down of limit count: ALL
count
---------------------------------------------------------------------
12000
(1 row)

SELECT count(*) FROM lineitem OFFSET 0 LIMIT null;
DEBUG: push down of limit count: ALL
count
---------------------------------------------------------------------
12000
(1 row)

-- check if we push the right limit when both offset and limit are given
SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey OFFSET 1 LIMIT 3;
DEBUG: push down of limit count: 4
l_orderkey
---------------------------------------------------------------------
1
1
1
(3 rows)

SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey OFFSET null LIMIT 1;
DEBUG: push down of limit count: 1
l_orderkey
---------------------------------------------------------------------
1
(1 row)

-- check if we can correctly push the limit when it is all
SELECT l_orderkey FROM lineitem WHERE l_orderkey < 2 LIMIT all;
DEBUG: push down of limit count: ALL
l_orderkey
---------------------------------------------------------------------
1
1
1
1
1
1
(6 rows)

SELECT l_orderkey FROM lineitem WHERE l_orderkey < 2 OFFSET 2 LIMIT all;
DEBUG: push down of limit count: ALL
l_orderkey
---------------------------------------------------------------------
1
1
1
1
(4 rows)

SET client_min_messages TO NOTICE;
-- non constants should not push down
CREATE OR REPLACE FUNCTION my_limit()
Expand Down
19 changes: 19 additions & 0 deletions src/test/regress/sql/multi_limit_clause.sql
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,25 @@ SELECT
ORDER BY 2 DESC, 1
LIMIT 5;

-- check if we can correctly push the limit when it is null
SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey LIMIT null;

SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey OFFSET 1 LIMIT null;

SELECT count(*) FROM lineitem LIMIT null;

SELECT count(*) FROM lineitem OFFSET 0 LIMIT null;

-- check if we push the right limit when both offset and limit are given
SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey OFFSET 1 LIMIT 3;

SELECT l_orderkey FROM lineitem WHERE l_orderkey < 3 ORDER BY l_orderkey OFFSET null LIMIT 1;

-- check if we can correctly push the limit when it is all
SELECT l_orderkey FROM lineitem WHERE l_orderkey < 2 LIMIT all;

SELECT l_orderkey FROM lineitem WHERE l_orderkey < 2 OFFSET 2 LIMIT all;

SET client_min_messages TO NOTICE;

-- non constants should not push down
Expand Down

0 comments on commit 9e1852e

Please sign in to comment.