Fix issues with sqlite field parsing.

The previous attempt would still fail on unions or derived table join
queries. This new approach is a bit slower but more robust.

Refs #3972
This commit is contained in:
mark_story 2014-11-12 20:49:19 -05:00
parent 93a6fd5648
commit 6092c168a9
2 changed files with 38 additions and 14 deletions

View file

@ -302,9 +302,15 @@ class Sqlite extends DboSource {
$querystring = $results->queryString;
if (stripos($querystring, 'SELECT') === 0 && stripos($querystring, 'FROM') > 0) {
$selectpart = substr($querystring, 7);
$selects = String::tokenize($selectpart, ',', '(', ')');
$last = count($selects) - 1;
$selects[$last] = trim(substr($selects[$last], 0, stripos($selects[$last], 'FROM')));
$selects = array();
foreach (String::tokenize($selectpart, ',', '(', ')') as $part) {
$fromPos = stripos($part, ' FROM ');
if ($fromPos !== false) {
$selects[] = trim(substr($part, 0, $fromPos));
break;
}
$selects[] = $part;
}
} elseif (strpos($querystring, 'PRAGMA table_info') === 0) {
$selects = array('cid', 'name', 'type', 'notnull', 'dflt_value', 'pk');
} elseif (strpos($querystring, 'PRAGMA index_list') === 0) {

View file

@ -527,19 +527,37 @@ class SqliteTest extends CakeTestCase {
$this->loadFixtures('User');
$sql = 'SELECT "User"."id", "User"."user", "User"."password", "User"."created", (1 + 1) AS "two" ' .
'FROM "users" AS "User" WHERE ' .
'"User"."id" IN (SELECT MAX("id") FROM "users")';
'"User"."id" IN (SELECT MAX("id") FROM "users") ' .
'OR "User.id" IN (5, 6, 7, 8)';
$result = $this->Dbo->fetchRow($sql);
$this->assertArrayHasKey('User', $result);
$this->assertArrayHasKey('0', $result);
$this->assertCount(2, $result, 'Too many top level keys');
$this->assertCount(4, $result['User'], 'Too many keys');
$this->assertCount(1, $result['0'], 'Too many keys');
$this->assertArrayHasKey('id', $result['User']);
$this->assertArrayHasKey('user', $result['User']);
$this->assertArrayHasKey('password', $result['User']);
$this->assertArrayHasKey('created', $result['User']);
$this->assertArrayHasKey('two', $result['0']);
$expected = array(
'User' => array(
'id' => 4,
'user' => 'garrett',
'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
'created' => '2007-03-17 01:22:23'
),
0 => array(
'two' => 2
)
);
$this->assertEquals($expected, $result);
$sql = 'SELECT "User"."id", "User"."user" ' .
'FROM "users" AS "User" WHERE "User"."id" = 4 ' .
'UNION ' .
'SELECT "User"."id", "User"."user" ' .
'FROM "users" AS "User" WHERE "User"."id" = 3';
$result = $this->Dbo->fetchRow($sql);
$expected = array(
'User' => array(
'id' => 3,
'user' => 'larry',
),
);
$this->assertEquals($expected, $result);
}
}