BlobTest.php 5.28 KB
Newer Older
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL\Functional;

5
use Doctrine\DBAL\Driver\OCI8\Driver as OCI8Driver;
6
use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver;
7
use Doctrine\DBAL\FetchMode;
8
use Doctrine\DBAL\ParameterType;
Sergei Morozov's avatar
Sergei Morozov committed
9
use Doctrine\DBAL\Schema\Table;
10
use Doctrine\DBAL\Types\Type;
Sergei Morozov's avatar
Sergei Morozov committed
11
use Doctrine\Tests\DbalFunctionalTestCase;
12

13 14
use function fopen;
use function str_repeat;
15
use function stream_get_contents;
16

Sergei Morozov's avatar
Sergei Morozov committed
17
class BlobTest extends DbalFunctionalTestCase
18
{
19
    protected function setUp(): void
20 21 22
    {
        parent::setUp();

23 24 25 26 27 28
        if ($this->connection->getDriver() instanceof PDOOracleDriver) {
            // inserting BLOBs as streams on Oracle requires Oracle-specific SQL syntax which is currently not supported
            // see http://php.net/manual/en/pdo.lobs.php#example-1035
            $this->markTestSkipped('DBAL doesn\'t support storing LOBs represented as streams using PDO_OCI');
        }

Sergei Morozov's avatar
Sergei Morozov committed
29 30
        $table = new Table('blob_table');
        $table->addColumn('id', 'integer');
31 32
        $table->addColumn('clobcolumn', 'text');
        $table->addColumn('blobcolumn', 'blob');
Sergei Morozov's avatar
Sergei Morozov committed
33
        $table->setPrimaryKey(['id']);
34

Sergei Morozov's avatar
Sergei Morozov committed
35
        $sm = $this->connection->getSchemaManager();
Sergei Morozov's avatar
Sergei Morozov committed
36
        $sm->dropAndCreateTable($table);
37 38
    }

39
    public function testInsert(): void
40
    {
Sergei Morozov's avatar
Sergei Morozov committed
41
        $ret = $this->connection->insert('blob_table', [
42
            'id'          => 1,
43 44
            'clobcolumn'   => 'test',
            'blobcolumn'   => 'test',
45 46 47 48 49 50
        ], [
            ParameterType::INTEGER,
            ParameterType::STRING,
            ParameterType::LARGE_OBJECT,
        ]);

51
        self::assertEquals(1, $ret);
52 53
    }

54
    public function testInsertProcessesStream(): void
55
    {
56 57 58
        // https://github.com/doctrine/dbal/issues/3290
        if ($this->connection->getDriver() instanceof OCI8Driver) {
            $this->markTestIncomplete('The oci8 driver does not support stream resources as parameters');
59 60 61
        }

        $longBlob = str_repeat('x', 4 * 8192); // send 4 chunks
Sergei Morozov's avatar
Sergei Morozov committed
62
        $this->connection->insert('blob_table', [
63
            'id'        => 1,
64 65
            'clobcolumn' => 'ignored',
            'blobcolumn' => fopen('data://text/plain,' . $longBlob, 'r'),
66 67 68 69 70 71 72 73 74
        ], [
            ParameterType::INTEGER,
            ParameterType::STRING,
            ParameterType::LARGE_OBJECT,
        ]);

        $this->assertBlobContains($longBlob);
    }

75
    public function testSelect(): void
76
    {
Sergei Morozov's avatar
Sergei Morozov committed
77
        $this->connection->insert('blob_table', [
Sergei Morozov's avatar
Sergei Morozov committed
78
            'id'          => 1,
79 80
            'clobcolumn'   => 'test',
            'blobcolumn'   => 'test',
Sergei Morozov's avatar
Sergei Morozov committed
81 82 83 84 85
        ], [
            ParameterType::INTEGER,
            ParameterType::STRING,
            ParameterType::LARGE_OBJECT,
        ]);
86 87 88 89

        $this->assertBlobContains('test');
    }

90
    public function testUpdate(): void
91
    {
Sergei Morozov's avatar
Sergei Morozov committed
92
        $this->connection->insert('blob_table', [
Sergei Morozov's avatar
Sergei Morozov committed
93
            'id' => 1,
94 95
            'clobcolumn' => 'test',
            'blobcolumn' => 'test',
Sergei Morozov's avatar
Sergei Morozov committed
96 97 98 99 100
        ], [
            ParameterType::INTEGER,
            ParameterType::STRING,
            ParameterType::LARGE_OBJECT,
        ]);
101

102
        $this->connection->update('blob_table', ['blobcolumn' => 'test2'], ['id' => 1], [
Sergei Morozov's avatar
Sergei Morozov committed
103 104 105
            ParameterType::LARGE_OBJECT,
            ParameterType::INTEGER,
        ]);
106 107 108 109

        $this->assertBlobContains('test2');
    }

110
    public function testUpdateProcessesStream(): void
111
    {
112 113 114
        // https://github.com/doctrine/dbal/issues/3290
        if ($this->connection->getDriver() instanceof OCI8Driver) {
            $this->markTestIncomplete('The oci8 driver does not support stream resources as parameters');
115 116
        }

Sergei Morozov's avatar
Sergei Morozov committed
117
        $this->connection->insert('blob_table', [
118
            'id'          => 1,
119 120
            'clobcolumn'   => 'ignored',
            'blobcolumn'   => 'test',
121 122 123 124 125 126
        ], [
            ParameterType::INTEGER,
            ParameterType::STRING,
            ParameterType::LARGE_OBJECT,
        ]);

Sergei Morozov's avatar
Sergei Morozov committed
127
        $this->connection->update('blob_table', [
128
            'id'          => 1,
129
            'blobcolumn'   => fopen('data://text/plain,test2', 'r'),
130 131 132 133 134 135 136 137
        ], ['id' => 1], [
            ParameterType::INTEGER,
            ParameterType::LARGE_OBJECT,
        ]);

        $this->assertBlobContains('test2');
    }

138
    public function testBindParamProcessesStream(): void
139
    {
140 141
        if ($this->connection->getDriver() instanceof OCI8Driver) {
            $this->markTestIncomplete('The oci8 driver does not support stream resources as parameters');
142 143
        }

Sergei Morozov's avatar
Sergei Morozov committed
144 145 146
        $stmt = $this->connection->prepare(
            "INSERT INTO blob_table(id, clobcolumn, blobcolumn) VALUES (1, 'ignored', ?)"
        );
147 148 149 150 151 152 153 154 155 156 157 158

        $stream = null;
        $stmt->bindParam(1, $stream, ParameterType::LARGE_OBJECT);

        // Bind param does late binding (bind by reference), so create the stream only now:
        $stream = fopen('data://text/plain,test', 'r');

        $stmt->execute();

        $this->assertBlobContains('test');
    }

159
    private function assertBlobContains(string $text): void
160
    {
161
        $rows = $this->connection->query('SELECT blobcolumn FROM blob_table')->fetchAll(FetchMode::COLUMN);
162

Gabriel Caruso's avatar
Gabriel Caruso committed
163
        self::assertCount(1, $rows);
164

Sergei Morozov's avatar
Sergei Morozov committed
165
        $blobValue = Type::getType('blob')->convertToPHPValue($rows[0], $this->connection->getDatabasePlatform());
166

167
        self::assertIsResource($blobValue);
168
        self::assertEquals($text, stream_get_contents($blobValue));
169
    }
170
}