Passed
Push — master ( 31f988...5e67da )
by Eugene
02:06
created

PrepareTest::provideSeqScan()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 9
rs 10
1
<?php
2
3
/**
4
 * This file is part of the tarantool/client package.
5
 *
6
 * (c) Eugene Leonovich <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Tarantool\Client\Tests\Integration\Requests;
15
16
use Tarantool\Client\Exception\RequestFailed;
17
use Tarantool\Client\PreparedStatement;
18
use Tarantool\Client\Tests\Integration\TestCase;
19
20
/**
21
 * @requires Tarantool >=2.3.2
22
 */
23
final class PrepareTest extends TestCase
24
{
25
    private function provideSeqScan() : string
26
    {
27
        /**
28
         * SEQSCAN keyword is explicitly allowing to use seqscan:
29
         * https://github.com/tarantool/tarantool/commit/77648827326ad268ec0ffbcd620c2371b65ef2b4
30
         * It was introduced in Tarantool 2.11.0-rc1. If compat.sql_seq_scan_default set to "new"
31
         * (default value since 3.0), query returns error when trying to scan without keyword.
32
         */
33
        return $this->tarantoolVersionSatisfies('>=2.11.0-rc1') ? 'SEQSCAN' : '';
34
    }
35
36
    public function testPreparePreparesSqlStatement() : void
37
    {
38
        [$preparedCountBefore] = $this->client->evaluate('return box.info.sql().cache.stmt_count');
0 ignored issues
show
Bug introduced by
The method evaluate() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

38
        /** @scrutinizer ignore-call */ 
39
        [$preparedCountBefore] = $this->client->evaluate('return box.info.sql().cache.stmt_count');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
39
        $stmt = $this->client->prepare('SELECT ?');
40
        [$preparedCountAfter] = $this->client->evaluate('return box.info.sql().cache.stmt_count');
41
42
        try {
43
            self::assertSame($preparedCountBefore + 1, $preparedCountAfter);
44
            self::assertIsInt($stmt->getId());
45
            self::assertSame(1, $stmt->getBindCount());
46
            self::assertSame([['?', 'ANY']], $stmt->getBindMetadata());
47
            // If the data type of NULL cannot be determined from context, it is BOOLEAN.
48
            // @see https://www.tarantool.io/en/doc/2.2/reference/reference_sql/sql/#column-definition-data-type
49
            $metaColumnName = $this->tarantoolVersionSatisfies('<2.6.0') ? '?' : 'COLUMN_1';
50
            self::assertSame([[$metaColumnName, 'boolean']], $stmt->getMetadata());
51
        } finally {
52
            $stmt->close();
53
        }
54
    }
55
56
    public function testExecuteQueryReturnsResult() : void
57
    {
58
        $stmt = $this->client->prepare('SELECT :v1, :v2');
59
60
        $selectResult1 = $stmt->executeQuery([':v1' => 1], [':v2' => 2]);
61
        $selectResult2 = $stmt->executeQuery([':v1' => 3], [':v2' => 4]);
62
63
        try {
64
            if ($this->tarantoolVersionSatisfies('<2.6.0')) {
65
                self::assertSame([':v1' => 1, ':v2' => 2], $selectResult1[0]);
66
                self::assertSame([':v1' => 3, ':v2' => 4], $selectResult2[0]);
67
            } else {
68
                self::assertSame(['COLUMN_1' => 1, 'COLUMN_2' => 2], $selectResult1[0]);
69
                self::assertSame(['COLUMN_1' => 3, 'COLUMN_2' => 4], $selectResult2[0]);
70
            }
71
        } finally {
72
            $stmt->close();
73
        }
74
    }
75
76
    /**
77
     * @sql DROP TABLE IF EXISTS prepare_execute
78
     * @sql CREATE TABLE prepare_execute (id INTEGER PRIMARY KEY, name VARCHAR(50))
79
     */
80
    public function testExecuteUpdateUpdatesRows() : void
81
    {
82
        $stmt = $this->client->prepare('INSERT INTO prepare_execute VALUES(:id, :name)');
83
84
        $insertResult1 = $stmt->executeUpdate(1, 'foo');
85
        $insertResult2 = $stmt->executeUpdate([':name' => 'bar'], [':id' => 2]);
86
87
        $seqScan = self::provideSeqScan();
0 ignored issues
show
Bug Best Practice introduced by
The method Tarantool\Client\Tests\I...eTest::provideSeqScan() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

87
        /** @scrutinizer ignore-call */ 
88
        $seqScan = self::provideSeqScan();
Loading history...
88
        $selectResult = $this->client->executeQuery("SELECT * FROM $seqScan prepare_execute ORDER BY id");
89
90
        try {
91
            self::assertSame(1, $insertResult1->count());
92
            self::assertSame(1, $insertResult2->count());
93
            self::assertSame([[1, 'foo'], [2, 'bar']], $selectResult->getData());
94
        } finally {
95
            $stmt->close();
96
        }
97
    }
98
99
    public function testCloseDeallocatesPreparedStatement() : void
100
    {
101
        $stmt = $this->client->prepare('SELECT ?');
102
103
        $this->expectPreparedStatementToBeDeallocatedOnce();
104
        $stmt->close();
105
    }
106
107
    public function testCloseDeallocatesPreparedInLuaSqlStatement() : void
108
    {
109
        [$data] = $this->client->evaluate("s = box.prepare('SELECT ?') return {
110
            id=s.stmt_id,
111
            bind_metadata=s.params,
112
            metadata=s.metadata,
113
            bind_count=s.param_count
114
        }");
115
116
        $stmt = new PreparedStatement(
117
            $this->client->getHandler(),
118
            $data['id'],
119
            $data['bind_count'],
120
            $data['bind_metadata'],
121
            $data['metadata']
122
        );
123
124
        $this->expectPreparedStatementToBeDeallocatedOnce();
125
        $stmt->close();
126
    }
127
128
    public function testCloseFailsOnNonexistentPreparedStatement() : void
129
    {
130
        $stmt = new PreparedStatement($this->client->getHandler(), 42, 0, [], []);
131
132
        $this->expectException(RequestFailed::class);
133
        $this->expectExceptionMessage('Prepared statement with id 42 does not exist');
134
        $stmt->close();
135
    }
136
137
    /**
138
     * @see https://github.com/tarantool/tarantool/issues/4825
139
     */
140
    public function testPrepareResetsPreviouslyBoundParameters() : void
141
    {
142
        $stmt = $this->client->prepare('SELECT :a, :b');
143
144
        // Bind parameters to the current statement
145
        $stmt->execute([':a' => 1], [':b' => 2]);
146
147
        $result = $stmt->executeQuery([':a' => 1]);
148
        self::assertSame([1, null], $result->getData()[0]);
149
150
        $result = $stmt->executeQuery();
151
        self::assertSame([null, null], $result->getData()[0]);
152
    }
153
}
154