From: daniel Date: Wed, 31 Oct 2012 14:27:57 +0000 (+0100) Subject: Fix handling of strings containing \0 in SQLite. X-Git-Tag: 1.31.0-rc.0~21757^2 X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/pie.php?a=commitdiff_plain;ds=sidebyside;h=9205808960477ad4ab6aa20dd8145e5d3e8b2d19;p=lhc%2Fweb%2Fwiklou.git Fix handling of strings containing \0 in SQLite. This change provides a workaround and test case for a problem in the sqlite library: SQLite truncates strings at ASCII value 00 aka \0. Strings containing \0 need to be represented in hexadecimal form. Reported to PHP as bug 63419 https://bugs.php.net/bug.php?id=63419 Change-Id: I2bbc445ffebd41e181edfc3201e6e5514de06142 --- diff --git a/includes/db/DatabaseSqlite.php b/includes/db/DatabaseSqlite.php index 1125d4f37a..d30d984fcc 100644 --- a/includes/db/DatabaseSqlite.php +++ b/includes/db/DatabaseSqlite.php @@ -705,6 +705,14 @@ class DatabaseSqlite extends DatabaseBase { function addQuotes( $s ) { if ( $s instanceof Blob ) { return "x'" . bin2hex( $s->fetch() ) . "'"; + } else if ( strpos( $s, "\0" ) !== false ) { + // SQLite doesn't support \0 in strings, so use the hex representation as a workaround. + // This is a known limitation of SQLite's mprintf function which PDO should work around, + // but doesn't. I have reported this to php.net as bug #63419: + // https://bugs.php.net/bug.php?id=63419 + // There was already a similar report for SQLite3::escapeString, bug #62361: + // https://bugs.php.net/bug.php?id=62361 + return "x'" . bin2hex( $s ) . "'"; } else { return $this->mConn->quote( $s ); } diff --git a/tests/phpunit/includes/db/DatabaseSqliteTest.php b/tests/phpunit/includes/db/DatabaseSqliteTest.php index 216de8424f..faa9abd986 100644 --- a/tests/phpunit/includes/db/DatabaseSqliteTest.php +++ b/tests/phpunit/includes/db/DatabaseSqliteTest.php @@ -54,6 +54,52 @@ class DatabaseSqliteTest extends MediaWikiTestCase { $this->assertEquals( count( $expected ), $i, 'Unexpected number of rows' ); } + public static function provideAddQuotes() { + return array( + array( // #0: empty + '', "''" + ), + array( // #1: simple + 'foo bar', "'foo bar'" + ), + array( // #2: including quote + 'foo\'bar', "'foo''bar'" + ), + array( // #3: including \0 (must be represented as hex, per https://bugs.php.net/bug.php?id=63419) + "x\0y", + "x'780079'", + ), + array( // #4: blob object (must be represented as hex) + new Blob( "hello" ), + "x'68656c6c6f'", + ), + ); + } + + /** + * @dataProvider provideAddQuotes() + */ + public function testAddQuotes( $value, $expected ) { + // check quoting + $db = new DatabaseSqliteStandalone( ':memory:' ); + $this->assertEquals( $expected, $db->addQuotes( $value ), 'string not quoted as expected' ); + + // ok, quoting works as expected, now try a round trip. + $re = $db->query( 'select ' . $db->addQuotes( $value ) ); + + $this->assertTrue( $re !== false, 'query failed' ); + + if ( $row = $re->fetchRow() ) { + if ( $value instanceof Blob ) { + $value = $value->fetch(); + } + + $this->assertEquals( $value, $row[0], 'string mangled by the database' ); + } else { + $this->fail( 'query returned no result' ); + } + } + public function testReplaceVars() { $this->assertEquals( 'foo', $this->replaceVars( 'foo' ), "Don't break anything accidentally" );