CodeIgniter icon indicating copy to clipboard operation
CodeIgniter copied to clipboard

Bug: inconsistent behavior of Query Builder limit 0

Open kenjis opened this issue 2 years ago • 8 comments

$this->db->limit(0)->get('table') returns no records. But $this->db->get('table', 0) returns all records.

Steps to reproduce:

		$config['database'] = './test.db';
		$config['dbdriver'] = 'sqlite3';
		$this->load->database($config);

		$this->load->dbforge();
		$fields = array(
			'name' => array(
				'type' => 'VARCHAR',
				'constraint' => '100',
			),
		);
		$this->dbforge->add_field('id');
		$this->dbforge->add_field($fields);
		$this->dbforge->create_table('test', TRUE);

		$data = array(
			array(
				'name' => 'My Name',
			),
			array(
				'name' => 'Another Name',
			),
			array(
				'name' => 'Other Name',
			),
		);
		$this->db->insert_batch('test', $data);

		echo '$this->db->limit(0)->get(\'test\')' . PHP_EOL;
		$query = $this->db->limit(0)->get('test');
		foreach ($query->result() as $row)
		{
			echo $row->name . PHP_EOL;
		}

		echo '$this->db->get(\'test\', 0)' . PHP_EOL;
		$query = $this->db->get('test', 0);
		foreach ($query->result() as $row)
		{
			echo $row->name . PHP_EOL;
		}

Result:

$this->db->limit(0)->get('test')
$this->db->get('test', 0)
My Name
Another Name
Other Name

kenjis avatar Dec 02 '23 20:12 kenjis

This is no a bug but design. $this->db->get('table', 0) means no limit not zero records.

poodle123 avatar Dec 06 '23 05:12 poodle123

No, it is not documented like that.

$query = $this->db->get('mytable', 10, 20); // Executes: SELECT * FROM mytable LIMIT 20, 10 https://www.codeigniter.com/userguide3/database/query_builder.html#selecting-data

https://github.com/bcit-ci/CodeIgniter/blob/63d037565dd782795021dcbd3b1ca6f8c8a509e4/system/database/DB_query_builder.php#L1438-L1443

kenjis avatar Dec 06 '23 06:12 kenjis

interesting. seems i misunderstood it then. I looked into DB_query_builder.php and it seems you are right. 0 should indeed be passed as a limit. Do you have the generated SQL query from your code? Just to be sure if the code is generated correctly or not?

poodle123 avatar Dec 06 '23 06:12 poodle123

$this->db->limit(0)->get('test')
SELECT *
FROM "test"
 LIMIT 0
$this->db->get('test', 0)
SELECT *
FROM "test"

kenjis avatar Dec 06 '23 06:12 kenjis

This is what I mentioned originally: 0 is not passed along due to this in the DB_query_builder.php:

	public function limit($value, $offset = 0)
	{
		is_null($value) OR $this->qb_limit = (int) $value;
		empty($offset) OR $this->qb_offset = (int) $offset;

		return $this;
	}

giving you all records when you set limit to zero.

If you change it to

public function limit($value, $offset = 0)
{
    $this->qb_limit = ($value === 0) ? 0 : (int) $value;
    empty($offset) OR $this->qb_offset = (int) $offset;

    return $this;
}

It should return what you expect. But again my understanding was that 0 was supposed to be interpreted als "do not set a limit" but I might be wrong.

poodle123 avatar Dec 06 '23 07:12 poodle123

No, no. limit(0) returns 0 records. It is a correct behavior. The issue is that $this->db->get('table', 0) returns all records.

php > $value = 0;
php > is_null($value) OR $qb_limit = (int) $value;
php > var_dump($qb_limit);
php shell code:1:
int(0)

But again my understanding was that 0 was supposed to be interpreted als "do not set a limit" but I might be wrong.

LIMIT 0 returns 0 records. Try MySQL or SQLite3 or PostgreSQL.

kenjis avatar Dec 06 '23 11:12 kenjis

I know that limit 0 returns 0 records in MySQL. But I understood the CI way differently: namely limit 0 = no limit,

I have no other ideas why limit is dropped. Sorry.

poodle123 avatar Dec 06 '23 12:12 poodle123

It seems CI3 distinguishes between $limit = 0 and $limit = NULL. So it is natural to interpret $limit = NULL means no limit, $limit = 0 means zero records. In fact, limit() behaves like that. Therefore I think the behavior of get() is a bug.

kenjis avatar Dec 07 '23 00:12 kenjis