1
+ --TEST--
2
+ Bug 64531 - SQLite3Result::fetchArray executes the query again
3
+ --EXTENSIONS--
4
+ sqlite3
5
+ --FILE--
6
+ <?php
7
+
8
+ require_once (__DIR__ . '/new_db.inc ' );
9
+
10
+ // Register two SQLite functions which call back to PHP -
11
+ echo "Register call counter function \n" ;
12
+
13
+ // "RECOGNISE(x)" returns x and increments a global counter of times x has been
14
+ // seen by the function.
15
+ function recognise (mixed $ value ) : mixed
16
+ {
17
+ $ GLOBALS ['seen ' ][$ value ] = ($ GLOBALS ['seen ' ][$ value ] ?? 0 ) + 1 ;
18
+ return $ value ;
19
+ };
20
+
21
+ // "RECOGNISED(x)" returns how many times x has been seen by RECOGNISE.
22
+ function recognised (mixed $ value ) : mixed
23
+ {
24
+ return $ GLOBALS ['seen ' ][$ value ];
25
+ }
26
+
27
+ $ db ->createFunction ('RECOGNISE ' , 'recognise ' );
28
+ $ db ->createFunction ('RECOGNISED ' , 'recognised ' );
29
+
30
+ echo "Create table \n\n" ;
31
+ // RECOGNISED(RECOGNISE(x)) should just return 1, 2, 3 for x, x, x if
32
+ // everything is going as expected, or 1, 1, 1 for x, y, z.
33
+ $ db ->exec ('CREATE TABLE letters (id INTEGER PRIMARY KEY, letter STRING, recognised_on_insert INTEGER) ' );
34
+
35
+ echo "Testing SQLite3Result behaviour on INSERT (no result set) when created using SQLite3Stmt->execute \n" ;
36
+ // The RECOGNISE function is called to generate the data before it is written,
37
+ // so this should look like VALUES ('a', 1), ('b', 1).
38
+ $ stmt = $ db ->prepare ('INSERT INTO letters (letter, recognised_on_insert) VALUES (:letter, RECOGNISED(RECOGNISE(:letter))) ' );
39
+
40
+ function checkInsertResult (SQLite3Result $ result , $ letter )
41
+ {
42
+ printf ("'%s' is inserted and has been seen %d times so far. \n" , $ letter , recognised ($ letter ));
43
+ printf ("calling fetchArray on the INSERT statement result. \n" );
44
+ while ($ row = $ result ->fetchArray (SQLITE3_ASSOC )) {
45
+ printf ("unexpected: a result came back. \n" );
46
+ var_dump ($ row );
47
+ }
48
+ $ check = recognised ($ letter );
49
+ printf (
50
+ "After calling fetch, '%s' has been seen %d times - %s. \n" ,
51
+ $ letter , $ check , $ check === 1 ? "OK " : "NOT OK "
52
+ );
53
+ printf ("calling fetchArray again - this will re-execute (see 79293). \n" );
54
+ while ($ row = $ result ->fetchArray (SQLITE3_ASSOC )) {
55
+ printf ("unexpected: a result came back. \n" );
56
+ var_dump ($ row );
57
+ }
58
+ $ check = recognised ($ letter );
59
+ printf (
60
+ "After calling fetch, '%s' has been seen %d times - %s. \n" ,
61
+ $ letter , $ check , $ check === 2 ? "OK " : "NOT OK "
62
+ );
63
+ }
64
+
65
+ function checkSelectResult (SQLite3Result $ result )
66
+ {
67
+ echo "Query executed, doing fetch \n" ;
68
+ while ($ row = $ result ->fetchArray (SQLITE3_ASSOC )) {
69
+ printf (
70
+ "letter '%s' was inserted with ID %2.d which has been seen %d times. The letter has now been seen %d times. \n" ,
71
+ $ row ['letter ' ],
72
+ $ row ['id ' ],
73
+ $ row ['id_recognised ' ],
74
+ $ row ['letter_recognised ' ]
75
+ );
76
+ }
77
+ }
78
+
79
+ foreach (str_split ("abc " ) as $ letter ) {
80
+ $ stmt ->bindValue (":letter " , $ letter );
81
+ $ result = $ stmt ->execute ();
82
+ checkInsertResult ($ result , $ letter );
83
+ }
84
+
85
+ echo "\nTesting SQLite3Result behaviour on INSERT (no result set) when created using SQLite3->query \n" ;
86
+ foreach (str_split ("ABC " ) as $ letter ) {
87
+ $ result = $ db ->query ("INSERT INTO letters (letter, recognised_on_insert) VALUES (' $ letter', RECOGNISED(RECOGNISE(' $ letter'))) " );
88
+ checkInsertResult ($ result , $ letter );
89
+ }
90
+
91
+ // Because we've run insert twice per letter above due to 79293, we now expect
92
+ // the DB to have (a, a, b, b, c, c, A, A, B, B, C, C). Let's check!
93
+ echo "\nTesting SQLite3Result behaviour on SELECT when created using SQLite3Stmt->execute \n" ;
94
+ $ stmt = $ db ->prepare (<<<SQL
95
+ SELECT
96
+ id,
97
+ RECOGNISE(letter) as letter,
98
+ RECOGNISED(id) AS id_recognised,
99
+ RECOGNISED(letter) as letter_recognised
100
+ FROM letters
101
+ WHERE id = RECOGNISE(?)
102
+ SQL );
103
+ for ($ i = 1 ; $ i <= 6 ; $ i ++) {
104
+ $ stmt ->bindValue (1 , $ i );
105
+ $ result = $ stmt ->execute ();
106
+ checkSelectResult ($ result );
107
+ }
108
+
109
+ echo "\nTesting SQLite3Result behaviour on SELECT when created using SQLite3->query \n" ;
110
+ for ($ i = 7 ; $ i <= 12 ; $ i ++) {
111
+ $ result = $ db ->query (<<<"SQL"
112
+ SELECT
113
+ id,
114
+ RECOGNISE(letter) as letter,
115
+ RECOGNISED(id) AS id_recognised,
116
+ RECOGNISED(letter) as letter_recognised
117
+ FROM letters
118
+ WHERE id = RECOGNISE( $ i)
119
+ SQL );
120
+ checkSelectResult ($ result );
121
+ }
122
+
123
+ echo "Final result \n\n" ;
124
+
125
+ foreach ($ GLOBALS ['seen ' ] as $ key => $ value ) {
126
+ printf ("%s | %3.d \n" , $ key , $ value );
127
+ }
128
+
129
+ echo "Closing database \n" ;
130
+
131
+ var_dump ($ db ->close ());
132
+ echo "Done \n" ;
133
+ ?>
134
+ --EXPECT--
135
+ Register call counter function
136
+ Create table
137
+
138
+ Testing SQLite3Result behaviour on INSERT (no result set) when created using SQLite3Stmt->execute
139
+ 'a' is inserted and has been seen 1 times so far.
140
+ calling fetchArray on the INSERT statement result.
141
+ After calling fetch, 'a' has been seen 1 times - OK.
142
+ calling fetchArray again - this will re-execute (see 79293).
143
+ After calling fetch, 'a' has been seen 2 times - OK.
144
+ 'b' is inserted and has been seen 1 times so far.
145
+ calling fetchArray on the INSERT statement result.
146
+ After calling fetch, 'b' has been seen 1 times - OK.
147
+ calling fetchArray again - this will re-execute (see 79293).
148
+ After calling fetch, 'b' has been seen 2 times - OK.
149
+ 'c' is inserted and has been seen 1 times so far.
150
+ calling fetchArray on the INSERT statement result.
151
+ After calling fetch, 'c' has been seen 1 times - OK.
152
+ calling fetchArray again - this will re-execute (see 79293).
153
+ After calling fetch, 'c' has been seen 2 times - OK.
154
+
155
+ Testing SQLite3Result behaviour on INSERT (no result set) when created using SQLite3->query
156
+ 'A' is inserted and has been seen 1 times so far.
157
+ calling fetchArray on the INSERT statement result.
158
+ After calling fetch, 'A' has been seen 1 times - OK.
159
+ calling fetchArray again - this will re-execute (see 79293).
160
+ After calling fetch, 'A' has been seen 2 times - OK.
161
+ 'B' is inserted and has been seen 1 times so far.
162
+ calling fetchArray on the INSERT statement result.
163
+ After calling fetch, 'B' has been seen 1 times - OK.
164
+ calling fetchArray again - this will re-execute (see 79293).
165
+ After calling fetch, 'B' has been seen 2 times - OK.
166
+ 'C' is inserted and has been seen 1 times so far.
167
+ calling fetchArray on the INSERT statement result.
168
+ After calling fetch, 'C' has been seen 1 times - OK.
169
+ calling fetchArray again - this will re-execute (see 79293).
170
+ After calling fetch, 'C' has been seen 2 times - OK.
171
+
172
+ Testing SQLite3Result behaviour on SELECT when created using SQLite3Stmt->execute
173
+ Query executed, doing fetch
174
+ letter 'a' was inserted with ID 1 which has been seen 1 times. The letter has now been seen 3 times.
175
+ Query executed, doing fetch
176
+ letter 'a' was inserted with ID 2 which has been seen 1 times. The letter has now been seen 4 times.
177
+ Query executed, doing fetch
178
+ letter 'b' was inserted with ID 3 which has been seen 1 times. The letter has now been seen 3 times.
179
+ Query executed, doing fetch
180
+ letter 'b' was inserted with ID 4 which has been seen 1 times. The letter has now been seen 4 times.
181
+ Query executed, doing fetch
182
+ letter 'c' was inserted with ID 5 which has been seen 1 times. The letter has now been seen 3 times.
183
+ Query executed, doing fetch
184
+ letter 'c' was inserted with ID 6 which has been seen 1 times. The letter has now been seen 4 times.
185
+
186
+ Testing SQLite3Result behaviour on SELECT when created using SQLite3->query
187
+ Query executed, doing fetch
188
+ letter 'A' was inserted with ID 7 which has been seen 1 times. The letter has now been seen 3 times.
189
+ Query executed, doing fetch
190
+ letter 'A' was inserted with ID 8 which has been seen 1 times. The letter has now been seen 4 times.
191
+ Query executed, doing fetch
192
+ letter 'B' was inserted with ID 9 which has been seen 1 times. The letter has now been seen 3 times.
193
+ Query executed, doing fetch
194
+ letter 'B' was inserted with ID 10 which has been seen 1 times. The letter has now been seen 4 times.
195
+ Query executed, doing fetch
196
+ letter 'C' was inserted with ID 11 which has been seen 1 times. The letter has now been seen 3 times.
197
+ Query executed, doing fetch
198
+ letter 'C' was inserted with ID 12 which has been seen 1 times. The letter has now been seen 4 times.
199
+ Final result
200
+
201
+ a | 4
202
+ b | 4
203
+ c | 4
204
+ A | 4
205
+ B | 4
206
+ C | 4
207
+ 1 | 1
208
+ 2 | 1
209
+ 3 | 1
210
+ 4 | 1
211
+ 5 | 1
212
+ 6 | 1
213
+ 7 | 1
214
+ 8 | 1
215
+ 9 | 1
216
+ 10 | 1
217
+ 11 | 1
218
+ 12 | 1
219
+ Closing database
220
+ bool(true)
221
+ Done
0 commit comments