Skip to content

Commit

Permalink
Merge pull request #611 from yajra/patch-pagination
Browse files Browse the repository at this point in the history
[8.x] Improve pagination performance.
  • Loading branch information
yajra committed Dec 6, 2020
2 parents d0f63b8 + a717c96 commit 0b67bff
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 18 deletions.
7 changes: 7 additions & 0 deletions src/Oci8/Query/Grammars/OracleGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ protected function compileTableExpression($sql, $constraint, $query)
return "select * from ({$sql}) where rownum {$constraint}";
}

if (! is_null($query->limit && ! is_null($query->offset))) {
$start = $query->offset + 1;
$finish = $query->offset + $query->limit;

return "select t2.* from ( select rownum AS \"rn\", t1.* from ({$sql}) t1 where rownum <= {$finish}) t2 where t2.\"rn\" >= {$start}";
}

return "select t2.* from ( select rownum AS \"rn\", t1.* from ({$sql}) t1 ) t2 where t2.\"rn\" {$constraint}";
}

Expand Down
52 changes: 34 additions & 18 deletions tests/Database/Oci8QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,10 @@ public function testSubSelectWhereIns()
$builder->select('*')->from('users')->whereIn('id', function ($q) {
$q->select('id')->from('users')->where('age', '>', 25)->take(3);
});
$this->assertEquals('select * from "USERS" where "ID" in (select t2.* from ( select rownum AS "rn", t1.* from (select "ID" from "USERS" where "AGE" > ?) t1 ) t2 where t2."rn" between 1 and 3)',
$builder->toSql());
$this->assertEquals(
'select * from "USERS" where "ID" in (select t2.* from ( select rownum AS "rn", t1.* from (select "ID" from "USERS" where "AGE" > ?) t1 where rownum <= 3) t2 where t2."rn" >= 1)',
$builder->toSql()
);
$this->assertEquals([25], $builder->getBindings());

$builder = $this->getBuilder();
Expand All @@ -279,8 +281,10 @@ public function testSubSelectWhereIns()
$builder->select('*')->from('users')->whereNotIn('id', function ($q) {
$q->select('id')->from('users')->where('age', '>', 25)->take(3);
});
$this->assertEquals('select * from "USERS" where "ID" not in (select t2.* from ( select rownum AS "rn", t1.* from (select "ID" from "USERS" where "AGE" > ?) t1 ) t2 where t2."rn" between 1 and 3)',
$builder->toSql());
$this->assertEquals(
'select * from "USERS" where "ID" not in (select t2.* from ( select rownum AS "rn", t1.* from (select "ID" from "USERS" where "AGE" > ?) t1 where rownum <= 3) t2 where t2."rn" >= 1)',
$builder->toSql()
);
$this->assertEquals([25], $builder->getBindings());
}

Expand Down Expand Up @@ -361,8 +365,10 @@ public function testOffset()
$connection = $builder->getConnection();
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->offset(10);
$this->assertEquals('select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" >= 11',
$builder->toSql());
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 10) t2 where t2."rn" >= 11',
$builder->toSql()
);
}

public function testLimitsAndOffsets()
Expand All @@ -371,36 +377,46 @@ public function testLimitsAndOffsets()
$connection = $builder->getConnection();
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->offset(5)->limit(10);
$this->assertEquals('select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" between 6 and 15',
$builder->toSql());
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 15) t2 where t2."rn" >= 6',
$builder->toSql()
);

$builder = $this->getBuilder();
$connection = $builder->getConnection();
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->skip(5)->take(10);
$this->assertEquals('select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" between 6 and 15',
$builder->toSql());
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 15) t2 where t2."rn" >= 6',
$builder->toSql()
);

$builder = $this->getBuilder();
$connection = $builder->getConnection();
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->skip(-5)->take(10);
$this->assertEquals('select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" between 1 and 10',
$builder->toSql());
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 10) t2 where t2."rn" >= 1',
$builder->toSql()
);

$builder = $this->getBuilder();
$connection = $builder->getConnection();
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->forPage(2, 15);
$this->assertEquals('select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" between 16 and 30',
$builder->toSql());
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 30) t2 where t2."rn" >= 16',
$builder->toSql()
);

$builder = $this->getBuilder();
$connection = $builder->getConnection();
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->forPage(-2, 15);
$this->assertEquals('select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" between 1 and 15',
$builder->toSql());
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 15) t2 where t2."rn" >= 1',
$builder->toSql()
);
}

public function testLimitAndOffsetToPaginateOne()
Expand All @@ -410,7 +426,7 @@ public function testLimitAndOffsetToPaginateOne()
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->offset(0)->limit(1);
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" between 1 and 1',
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 1) t2 where t2."rn" >= 1',
$builder->toSql()
);

Expand All @@ -419,7 +435,7 @@ public function testLimitAndOffsetToPaginateOne()
$connection->shouldReceive('getConfig')->andReturn('');
$builder->select('*')->from('users')->offset(1)->limit(1);
$this->assertEquals(
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 ) t2 where t2."rn" between 2 and 2',
'select t2.* from ( select rownum AS "rn", t1.* from (select * from "USERS") t1 where rownum <= 2) t2 where t2."rn" >= 2',
$builder->toSql()
);
}
Expand Down

0 comments on commit 0b67bff

Please sign in to comment.