Fix SQLite parsing fields incorrectly when using subqueries.

When using subqueries or joining against tables containing FROM the
results were bizzare and unexpected. By tokenizing the entire query we
can more accurately grab the fields.

Refs #3972
This commit is contained in:
mark_story 2014-11-11 23:13:44 -05:00
parent 2addee9808
commit 93a6fd5648
2 changed files with 29 additions and 6 deletions

View file

@ -300,12 +300,11 @@ class Sqlite extends DboSource {
// PDO::getColumnMeta is experimental and does not work with sqlite3,
// so try to figure it out based on the querystring
$querystring = $results->queryString;
if (stripos($querystring, 'SELECT') === 0) {
$last = strripos($querystring, 'FROM');
if ($last !== false) {
$selectpart = substr($querystring, 7, $last - 8);
$selects = String::tokenize($selectpart, ',', '(', ')');
}
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')));
} 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

@ -518,4 +518,28 @@ class SqliteTest extends CakeTestCase {
$this->assertNotContains($scientificNotation, $result);
}
/**
* Test that fields are parsed out in a reasonable fashion.
*
* @return void
*/
public function testFetchRowColumnParsing() {
$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")';
$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']);
}
}