Always decode Blob objects from Database::addQuotes
authorErik Bernhardson <ebernhardson@wikimedia.org>
Fri, 31 Oct 2014 20:16:54 +0000 (13:16 -0700)
committerEBernhardson <ebernhardson@wikimedia.org>
Mon, 2 Feb 2015 17:43:12 +0000 (17:43 +0000)
The current API for Database::encodeBlob/Database::addQuotes requires
the code that is outputting binary data to have a database handle, so
that it may call Database::encodeBlob to get either a plain string or
a Blob object back. All database implementations other than MySQL
return a Blob object from Database::encodeBlob.

This is a rather inconvenient API, it tightly couples the creation of
binary data with the Database object unnecessarily.  If all database
objects accept a Blob via Database::addQuotes then code can simply
wrap its arguments in Blob and know that any database it ends up at
will be properly handled.

This patch changes the default implementation of Database::addQuotes
to recognize a Blob object was passed in, and use Blob::fetch to turn
it back into a string.  Database implementations other than MySQL all
handle this Blob object already.  The postgresql implementation had
to be adjusted slightly. Now when it sees a Blob object that it did
not create it will encode that appropriately.

Bug: 72367
Change-Id: I12fb4bd339be19137fffba2e47a70741382f6a8c

autoload.php
includes/db/Database.php
includes/db/DatabaseMssql.php
includes/db/DatabasePostgres.php

index 90cd074..32c9934 100644 (file)
@@ -881,6 +881,7 @@ $wgAutoloadLocalClasses = array(
        'PopulateRevisionLength' => __DIR__ . '/maintenance/populateRevisionLength.php',
        'PopulateRevisionSha1' => __DIR__ . '/maintenance/populateRevisionSha1.php',
        'PostgreSqlLockManager' => __DIR__ . '/includes/filebackend/lockmanager/DBLockManager.php',
+       'PostgresBlob' => __DIR__ . '/includes/db/DatabasePostgres.php',
        'PostgresField' => __DIR__ . '/includes/db/DatabasePostgres.php',
        'PostgresInstaller' => __DIR__ . '/includes/installer/PostgresInstaller.php',
        'PostgresTransactionState' => __DIR__ . '/includes/db/DatabasePostgres.php',
index 054f27a..8e76239 100644 (file)
@@ -2642,10 +2642,13 @@ abstract class DatabaseBase implements IDatabase {
        /**
         * Adds quotes and backslashes.
         *
-        * @param string $s
+        * @param string|Blob $s
         * @return string
         */
        public function addQuotes( $s ) {
+               if ( $s instanceof Blob ) {
+                       $s = $s->fetch();
+               }
                if ( $s === null ) {
                        return 'NULL';
                } else {
@@ -3909,10 +3912,13 @@ abstract class DatabaseBase implements IDatabase {
         * in result objects. Pass the object through this function to return the
         * original string.
         *
-        * @param string $b
+        * @param string|Blob $b
         * @return string
         */
        public function decodeBlob( $b ) {
+               if ( $b instanceof Blob ) {
+                       $b = $b->fetch();
+               }
                return $b;
        }
 
index a7bc6dd..e5ae766 100644 (file)
@@ -1131,7 +1131,7 @@ class DatabaseMssql extends DatabaseBase {
        }
 
        /**
-        * @param string $s
+        * @param string|Blob $s
         * @return string
         */
        public function addQuotes( $s ) {
index ce14d7a..0487b79 100644 (file)
@@ -1495,12 +1495,14 @@ SQL;
         * @return Blob
         */
        function encodeBlob( $b ) {
-               return new Blob( pg_escape_bytea( $this->mConn, $b ) );
+               return new PostgresBlob( pg_escape_bytea( $b ) );
        }
 
        function decodeBlob( $b ) {
-               if ( $b instanceof Blob ) {
+               if ( $b instanceof PostgresBlob ) {
                        $b = $b->fetch();
+               } elseif ( $b instanceof Blob ) {
+                       return $b->fetch();
                }
 
                return pg_unescape_bytea( $b );
@@ -1520,7 +1522,12 @@ SQL;
                } elseif ( is_bool( $s ) ) {
                        return intval( $s );
                } elseif ( $s instanceof Blob ) {
-                       return "'" . $s->fetch( $s ) . "'";
+                       if ( $s instanceof PostgresBlob ) {
+                               $s = $s->fetch();
+                       } else {
+                               $s = pg_escape_bytea( $this->mConn, $s->fetch() );
+                       }
+                       return "'$s'";
                }
 
                return "'" . pg_escape_string( $this->mConn, $s ) . "'";
@@ -1692,3 +1699,5 @@ SQL;
                return wfBaseConvert( substr( sha1( $lockName ), 0, 15 ), 16, 10 );
        }
 } // end DatabasePostgres class
+
+class PostgresBlob extends Blob {}