Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
// +----------------------------------------------------------------------+
3
// | PHP versions 4 and 5                                                 |
4
// +----------------------------------------------------------------------+
5
// | Copyright (c) 1998-2006 Manuel Lemos, Paul Cooper                    |
6
// | All rights reserved.                                                 |
7
// +----------------------------------------------------------------------+
8
// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
9
// | API as well as database abstraction for PHP applications.            |
10
// | This LICENSE is in the BSD license style.                            |
11
// |                                                                      |
12
// | Redistribution and use in source and binary forms, with or without   |
13
// | modification, are permitted provided that the following conditions   |
14
// | are met:                                                             |
15
// |                                                                      |
16
// | Redistributions of source code must retain the above copyright       |
17
// | notice, this list of conditions and the following disclaimer.        |
18
// |                                                                      |
19
// | Redistributions in binary form must reproduce the above copyright    |
20
// | notice, this list of conditions and the following disclaimer in the  |
21
// | documentation and/or other materials provided with the distribution. |
22
// |                                                                      |
23
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
24
// | Lukas Smith nor the names of his contributors may be used to endorse |
25
// | or promote products derived from this software without specific prior|
26
// | written permission.                                                  |
27
// |                                                                      |
28
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
29
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
30
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
31
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
32
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
33
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
34
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
35
// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
36
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
37
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
38
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
39
// | POSSIBILITY OF SUCH DAMAGE.                                          |
40
// +----------------------------------------------------------------------+
41
// | Author: Paul Cooper <pgc@ucecom.com>                                 |
42
// +----------------------------------------------------------------------+
43
//
44
// $Id: MDB2_usage_testcase.php,v 1.100 2006/12/19 22:46:48 quipo Exp $
45
 
46
require_once 'MDB2_testcase.php';
47
 
48
class MDB2_Usage_TestCase extends MDB2_TestCase {
49
    /**
50
     * Test typed data storage and retrieval
51
     *
52
     * This tests typed data storage and retrieval by executing a single
53
     * prepared query and then selecting the data back from the database
54
     * and comparing the results
55
     */
56
    function testStorage() {
57
        $data = $this->getSampleData(1234);
58
 
59
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
60
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
61
        $result = $stmt->execute(array_values($data));
62
        $stmt->free();
63
 
64
        if (PEAR::isError($result)) {
65
            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
66
        }
67
 
68
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
69
        $result =& $this->db->query($query, $this->fields);
70
 
71
        if (PEAR::isError($result)) {
72
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
73
        }
74
 
75
        $this->verifyFetchedValues($result, 0, $data);
76
    }
77
 
78
    /**
79
     * Test fetchOne()
80
     *
81
     * This test bulk fetching of result data by using a prepared query to
82
     * insert an number of rows of data and then retrieving the data columns
83
     * one by one
84
     */
85
    function testFetchOne() {
86
        $data = array();
87
        $total_rows = 5;
88
 
89
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
90
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
91
 
92
        for ($row = 0; $row < $total_rows; $row++) {
93
            $data[$row] = $this->getSampleData($row);
94
            $result = $stmt->execute(array_values($data[$row]));
95
 
96
            if (PEAR::isError($result)) {
97
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
98
            }
99
        }
100
 
101
        $stmt->free();
102
 
103
        foreach ($this->fields as $field => $type) {
104
            for ($row = 0; $row < $total_rows; $row++) {
105
                $result =& $this->db->query('SELECT '.$field.' FROM users WHERE user_id='.$row, $type);
106
                $value = $result->fetchOne();
107
                if (PEAR::isError($value)) {
108
                    $this->assertTrue(false, 'Error fetching row '.$row.' for field '.$field.' of type '.$type);
109
                } else {
110
                    $this->assertEquals(strval($data[$row][$field]), strval(trim($value)), 'the query field '.$field.' of type '.$type.' for row '.$row);
111
                    $result->free();
112
                }
113
            }
114
        }
115
    }
116
 
117
    /**
118
     * Test fetchCol()
119
     *
120
     * Test fetching a column of result data. Two different columns are retrieved
121
     */
122
    function testFetchCol() {
123
        $data = array();
124
        $total_rows = 5;
125
 
126
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
127
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
128
 
129
        for ($row = 0; $row < $total_rows; $row++) {
130
            $data[$row] = $this->getSampleData($row);
131
            $result = $stmt->execute(array_values($data[$row]));
132
 
133
            if (PEAR::isError($result)) {
134
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
135
            }
136
        }
137
 
138
        $stmt->free();
139
 
140
        $first_col = array();
141
        for ($row = 0; $row < $total_rows; $row++) {
142
            $first_col[$row] = "user_$row";
143
        }
144
 
145
        $second_col = array();
146
        for ($row = 0; $row < $total_rows; $row++) {
147
            $second_col[$row] = $row;
148
        }
149
 
150
        $query = 'SELECT user_name, user_id FROM users ORDER BY user_name';
151
        $result =& $this->db->query($query, array('text', 'integer'));
152
        if (PEAR::isError($result)) {
153
            $this->assertTrue(false, 'Error during query');
154
        }
155
        $values = $result->fetchCol(0);
156
        if (PEAR::isError($values)) {
157
            $this->assertTrue(false, 'Error fetching first column');
158
        } else {
159
            $this->assertEquals($first_col, $values);
160
        }
161
        $result->free();
162
 
163
        $query = 'SELECT user_name, user_id FROM users ORDER BY user_name';
164
        $result =& $this->db->query($query, array('text', 'integer'));
165
        if (PEAR::isError($result)) {
166
            $this->assertTrue(false, 'Error during query');
167
        }
168
        $values = $result->fetchCol(1);
169
        if (PEAR::isError($values)) {
170
            $this->assertTrue(false, 'Error fetching second column');
171
        } else {
172
            $this->assertEquals($second_col, $values);
173
        }
174
        $result->free();
175
    }
176
 
177
    /**
178
     * Test fetchAll()
179
     *
180
     * Test fetching an entire result set in one shot.
181
     */
182
    function testFetchAll() {
183
        $data = array();
184
        $total_rows = 5;
185
 
186
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
187
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
188
 
189
        for ($row = 0; $row < $total_rows; $row++) {
190
            $data[$row] = $this->getSampleData($row);
191
            $result = $stmt->execute(array_values($data[$row]));
192
 
193
            if (PEAR::isError($result)) {
194
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
195
            }
196
        }
197
        $fields = array_keys($data[0]);
198
        $query = 'SELECT '. implode (', ', $fields). ' FROM users ORDER BY user_name';
199
 
200
        $stmt->free();
201
 
202
        $result =& $this->db->query($query, $this->fields);
203
        if (PEAR::isError($result)) {
204
            $this->assertTrue(false, 'Error during query');
205
        }
206
        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC);
207
        if (PEAR::isError($values)) {
208
            $this->assertTrue(false, 'Error fetching the result set');
209
        } else {
210
            for ($i=0; $i<$total_rows; $i++) {
211
                foreach ($data[$i] as $key => $val) {
212
                    $this->assertEquals(strval($val), strval($values[$i][$key]), 'Row #'.$i.' ['.$key.']');
213
                }
214
            }
215
        }
216
        $result->free();
217
 
218
        //test $rekey=true
219
        $result =& $this->db->query('SELECT user_id, user_name FROM users ORDER BY user_id', $this->fields);
220
        if (PEAR::isError($result)) {
221
            $this->assertTrue(false, 'Error during query');
222
        }
223
        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true);
224
        if (PEAR::isError($values)) {
225
            $this->assertTrue(false, 'Error fetching the result set');
226
        } else {
227
            for ($i=0; $i<$total_rows; $i++) {
228
                list($id, $name) = each($values);
229
                $this->assertEquals($data[$i]['user_id'],   $id,   'Row #'.$i.' ["user_id"]');
230
                $this->assertEquals($data[$i]['user_name'], $name, 'Row #'.$i.' ["user_name"]');
231
            }
232
        }
233
        $result->free();
234
 
235
 
236
        //test $rekey=true, $force_array=true
237
        $result =& $this->db->query('SELECT user_id, user_name FROM users ORDER BY user_id', $this->fields);
238
        if (PEAR::isError($result)) {
239
            $this->assertTrue(false, 'Error during query');
240
        }
241
        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true);
242
        if (PEAR::isError($values)) {
243
            $this->assertTrue(false, 'Error fetching the result set');
244
        } else {
245
            for ($i=0; $i<$total_rows; $i++) {
246
                list($id, $value) = each($values);
247
                $this->assertEquals($data[$i]['user_id'],   $id,                 'Row #'.$i.' ["user_id"]');
248
                $this->assertEquals($data[$i]['user_name'], $value['user_name'], 'Row #'.$i.' ["user_name"]');
249
            }
250
        }
251
        $result->free();
252
 
253
        //test $rekey=true, $force_array=true, $group=true
254
        $result =& $this->db->query('SELECT user_password, user_name FROM users ORDER BY user_name', $this->fields);
255
        if (PEAR::isError($result)) {
256
            $this->assertTrue(false, 'Error during query');
257
        }
258
        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true, true);
259
        if (PEAR::isError($values)) {
260
            $this->assertTrue(false, 'Error fetching the result set');
261
        } else {
262
            //all the records have the same user_password value
263
            $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows');
264
            $values = $values[$data[0]['user_password']];
265
            for ($i=0; $i<$total_rows; $i++) {
266
                $this->assertEquals($data[$i]['user_name'], $values[$i]['user_name'], 'Row #'.$i.' ["user_name"]');
267
            }
268
        }
269
        $result->free();
270
 
271
        //test $rekey=true, $force_array=true, $group=false (with non unique key)
272
        $result =& $this->db->query('SELECT user_password, user_name FROM users ORDER BY user_name', $this->fields);
273
        if (PEAR::isError($result)) {
274
            $this->assertTrue(false, 'Error during query');
275
        }
276
        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true, false);
277
        if (PEAR::isError($values)) {
278
            $this->assertTrue(false, 'Error fetching the result set');
279
        } else {
280
            //all the records have the same user_password value, they are overwritten
281
            $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows');
282
            $key = $data[0]['user_password'];
283
            $this->assertEquals(1, count($values[$key]), 'Error: incorrect number of returned rows');
284
            $this->assertEquals($data[4]['user_name'], $values[$key]['user_name']);
285
        }
286
        $result->free();
287
    }
288
 
289
    /**
290
     * Test different fetch modes
291
     *
292
     * Test fetching results using different fetch modes
293
     * NOTE: several tests still missing
294
     */
295
    function testFetchModes() {
296
        $data = array();
297
        $total_rows = 5;
298
 
299
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
300
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
301
 
302
        for ($row = 0; $row < $total_rows; $row++) {
303
            $data[$row] = $this->getSampleData($row);
304
            $result = $stmt->execute(array_values($data[$row]));
305
 
306
            if (PEAR::isError($result)) {
307
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
308
            }
309
        }
310
 
311
        $stmt->free();
312
 
313
        // test ASSOC
314
        $query = 'SELECT A.user_name FROM users A, users B WHERE A.user_id = B.user_id';
315
        $value = $this->db->queryRow($query, array($this->fields['user_name']), MDB2_FETCHMODE_ASSOC);
316
        if (PEAR::isError($value)) {
317
            $this->assertTrue(false, 'Error fetching the result set');
318
        } else {
319
            $this->assertTrue(!empty($value['user_name']), 'Error fetching the associative result set from join');
320
        }
321
    }
322
 
323
    /**
324
     * Test multi_query option
325
     *
326
     * This test attempts to send multiple queries at once using the multi_query
327
     * option and then retrieves each result.
328
     */
329
    function testMultiQuery() {
330
        $multi_query_orig = $this->db->getOption('multi_query');
331
        if (PEAR::isError($multi_query_orig)) {
332
            $this->assertTrue(false, 'Error getting multi_query option value: '.$multi_query_orig->getMessage());
333
            return;
334
        }
335
 
336
        $this->db->setOption('multi_query', true);
337
 
338
        $data = array();
339
        $total_rows = 5;
340
 
341
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
342
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
343
 
344
        for ($row = 0; $row < $total_rows; $row++) {
345
            $data[$row] = $this->getSampleData($row);
346
            $result = $stmt->execute(array_values($data[$row]));
347
 
348
            if (PEAR::isError($result)) {
349
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
350
            }
351
        }
352
 
353
        $stmt->free();
354
 
355
        $query = '';
356
        for ($row = 0; $row < $total_rows; $row++) {
357
            $query.= 'SELECT user_name FROM users WHERE user_id='.$row.';';
358
        }
359
        $result =& $this->db->query($query, 'text');
360
 
361
        for ($row = 0; $row < $total_rows; $row++) {
362
            $value = $result->fetchOne();
363
            if (PEAR::isError($value)) {
364
                $this->assertTrue(false, 'Error fetching row '.$row);
365
            } else {
366
                $this->assertEquals(strval($data[$row]['user_name']), strval(trim($value)), 'the query field username of type "text" for row '.$row);
367
            }
368
            if (PEAR::isError($result->nextResult())) {
369
                $this->assertTrue(false, 'Error moving result pointer');
370
            }
371
        }
372
 
373
        $result->free();
374
        $this->db->setOption('multi_query', $multi_query_orig);
375
    }
376
 
377
    /**
378
     * Test prepared queries
379
     *
380
     * Tests prepared queries, making sure they correctly deal with ?, !, and '
381
     */
382
    function testPreparedQueries() {
383
        $data = array(
384
            array(
385
                'user_name' => 'Sure!',
386
                'user_password' => 'Do work?',
387
                'user_id' => 1,
388
            ),
389
            array(
390
                'user_name' => 'For Sure!',
391
                'user_password' => "Doesn't?",
392
                'user_id' => 2,
393
            ),
394
        );
395
 
396
        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (?, ?, ?)";
397
        $stmt = $this->db->prepare($query, array('text', 'text', 'integer'), MDB2_PREPARE_MANIP);
398
 
399
        $text = $data[0]['user_name'];
400
        $question = $data[0]['user_password'];
401
        $userid = $data[0]['user_id'];
402
 
403
        // bind out of order
404
        $stmt->bindParam(0, $text);
405
        $stmt->bindParam(2, $userid);
406
        $stmt->bindParam(1, $question);
407
 
408
        $result = $stmt->execute();
409
        if (PEAR::isError($result)) {
410
            $this->assertTrue(true, 'Could not execute prepared query with question mark placeholders. Error: '.$error);
411
        }
412
 
413
        $text = $data[1]['user_name'];
414
        $question = $data[1]['user_password'];
415
        $userid = $data[1]['user_id'];
416
 
417
        $result = $stmt->execute();
418
        if (PEAR::isError($result)) {
419
            $this->assertTrue(true, 'Could not execute prepared query with bound parameters. Error: '.$error);
420
        }
421
        $stmt->free();
422
        $this->clearTables();
423
 
424
        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (:text, :question, :userid)";
425
        $stmt = $this->db->prepare($query, array('text', 'text', 'integer'), MDB2_PREPARE_MANIP);
426
 
427
        $stmt->bindValue('text', $data[0]['user_name']);
428
        $stmt->bindValue('question', $data[0]['user_password']);
429
        $stmt->bindValue('userid', $data[0]['user_id']);
430
 
431
        $result = $stmt->execute();
432
        if (PEAR::isError($result)) {
433
            $this->assertTrue(true, 'Could not execute prepared query with named placeholders. Error: '.$error);
434
        }
435
        $stmt->free();
436
 
437
        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (".$this->db->quote($data[1]['user_name'], 'text').", :question, :userid)";
438
        $stmt = $this->db->prepare($query, array('text', 'integer'), MDB2_PREPARE_MANIP);
439
 
440
        $stmt->bindValue('question', $data[1]['user_password']);
441
        $stmt->bindValue('userid', $data[1]['user_id']);
442
 
443
        $result = $stmt->execute();
444
        if (PEAR::isError($result)) {
445
            $this->assertTrue(true, 'Could not execute prepared query with named placeholders and a quoted text value in front. Error: '.$error);
446
        }
447
        $stmt->free();
448
 
449
        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_id=:user_id';
450
        $stmt = $this->db->prepare($query, array('integer'), array('text', 'text', 'integer'));
451
        foreach ($data as $row_data) {
452
            $result =& $stmt->execute(array('user_id' => $row_data['user_id']));
453
            if (PEAR::isError($result)) {
454
                $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared. Error: '.$result->getUserinfo());
455
                break;
456
            }
457
            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
458
            if (!is_array($row)) {
459
                $this->assertTrue(false, 'Prepared SELECT failed');
460
            } else {
461
                $diff = (array)array_diff($row, $row_data);
462
                $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
463
            }
464
        }
465
        $stmt->free();
466
 
467
        $row_data = reset($data);
468
        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_id='.$this->db->quote($row_data['user_id'], 'integer');
469
        $stmt = $this->db->prepare($query, null, array('text', 'text', 'integer'));
470
        $result =& $stmt->execute(array());
471
        if (PEAR::isError($result)) {
472
            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared statement with no placeholders. Error: '.$result->getUserinfo());
473
            break;
474
        }
475
        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
476
        if (!is_array($row)) {
477
            $this->assertTrue(false, 'Prepared SELECT failed');
478
        } else {
479
            $diff = (array)array_diff($row, $row_data);
480
            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
481
        }
482
        $stmt->free();
483
 
484
        $row_data = reset($data);
485
        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_name='.$this->db->quote($row_data['user_name'], 'text').' AND user_id = ? AND user_password='.$this->db->quote($row_data['user_password'], 'text');
486
        $stmt = $this->db->prepare($query, array('integer'), array('text', 'text', 'integer'));
487
        $result =& $stmt->execute(array($row_data['user_id']));
488
        if (PEAR::isError($result)) {
489
            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared with quoted text fields around a placeholder. Error: '.$result->getUserinfo());
490
            break;
491
        }
492
        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
493
        if (!is_array($row)) {
494
            $this->assertTrue(false, 'Prepared SELECT failed');
495
        } else {
496
            $diff = (array)array_diff($row, $row_data);
497
            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
498
        }
499
        $stmt->free();
500
 
501
        foreach ($this->db->sql_comments as $comment) {
502
            $query = 'SELECT user_name, user_password, user_id FROM users WHERE '.$comment['start'].' maps to class::foo() '.$comment['end'].' user_name=:username';
503
            $row_data = reset($data);
504
            $stmt = $this->db->prepare($query, array('text'), array('text', 'text', 'integer'));
505
            $result =& $stmt->execute(array('username' => $row_data['user_name']));
506
            if (PEAR::isError($result)) {
507
                $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared where a name parameter is contained in an SQL comment ('.$comment['start'].'). Error: '.$result->getUserinfo());
508
                break;
509
            }
510
            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
511
            if (!is_array($row)) {
512
                $this->assertTrue(false, 'Prepared SELECT failed');
513
            } else {
514
                $diff = (array)array_diff($row, $row_data);
515
                $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
516
            }
517
            $stmt->free();
518
        }
519
 
520
        $row_data = reset($data);
521
        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_name=:username OR user_password=:username';
522
        $stmt = $this->db->prepare($query, array('text'), array('text', 'text', 'integer'));
523
        $result =& $stmt->execute(array('username' => $row_data['user_name']));
524
        if (PEAR::isError($result)) {
525
            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared where the same named parameter is used twice. Error: '.$result->getUserinfo());
526
            break;
527
        }
528
        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
529
        if (!is_array($row)) {
530
            $this->assertTrue(false, 'Prepared SELECT failed');
531
        } else {
532
            $diff = (array)array_diff($row, $row_data);
533
            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
534
        }
535
        $stmt->free();
536
    }
537
 
538
    /**
539
     * Test _skipDelimitedStrings(), used by prepare()
540
     *
541
     * If the placeholder is contained within a delimited string, it must be skipped,
542
     * and the cursor position must be advanced
543
     */
544
    function testSkipDelimitedStrings() {
545
        //test correct placeholder
546
        $query = 'SELECT what FROM tbl WHERE x = ?';
547
        $position = 0;
548
        $p_position = strpos($query, '?');
549
        $this->assertEquals($position, $this->db->_skipDelimitedStrings($query, $position, $p_position), 'Error: the cursor position has changed');
550
 
551
        //test placeholder within a quoted string
552
        $query = 'SELECT what FROM tbl WHERE x = '. $this->db->string_quoting['start'] .'blah?blah'. $this->db->string_quoting['end'] .' AND y = ?';
553
        $position = 0;
554
        $p_position = strpos($query, '?');
555
        $new_pos = $this->db->_skipDelimitedStrings($query, $position, $p_position);
556
        $this->assertTrue($position != $new_pos, 'Error: the cursor position was not advanced');
557
 
558
        //test placeholder within a comment
559
        foreach ($this->db->sql_comments as $comment) {
560
            $query = 'SELECT what FROM tbl WHERE x = '. $comment['start'] .'blah?blah'. $comment['end'] .' AND y = ?';
561
            $position = 0;
562
            $p_position = strpos($query, '?');
563
            $new_pos = $this->db->_skipDelimitedStrings($query, $position, $p_position);
564
            $this->assertTrue($position != $new_pos, 'Error: the cursor position was not advanced');
565
        }
566
 
567
        //add some tests for named placeholders and for identifier_quoting
568
    }
569
 
570
    /**
571
     * Test retrieval of result metadata
572
     *
573
     * This tests the result metadata by executing a prepared query and
574
     * select the data, and checking the result contains the correct
575
     * number of columns and that the column names are in the correct order
576
     */
577
    function testMetadata() {
578
        $data = $this->getSampleData(1234);
579
 
580
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
581
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
582
 
583
        $result = $stmt->execute(array_values($data));
584
        $stmt->free();
585
 
586
        if (PEAR::isError($result)) {
587
            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
588
        }
589
 
590
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
591
        $result =& $this->db->query($query, $this->fields);
592
 
593
        if (PEAR::isError($result)) {
594
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
595
        }
596
 
597
        $numcols = $result->numCols();
598
 
599
        $this->assertEquals(count($this->fields), $numcols, "The query result returned an incorrect number of columns unlike expected");
600
 
601
        $column_names = $result->getColumnNames();
602
        $fields = array_keys($this->fields);
603
        for ($column = 0; $column < $numcols; $column++) {
604
            $this->assertEquals($column, $column_names[$fields[$column]], "The query result column \"".$fields[$column]."\" was returned in an incorrect position");
605
        }
606
 
607
    }
608
 
609
    /**
610
     * Test storage and retrieval of nulls
611
     *
612
     * This tests null storage and retrieval by successively inserting,
613
     * selecting, and testing a number of null / not null values
614
     */
615
    function testNulls() {
616
        $portability = $this->db->getOption('portability');
617
        if ($portability & MDB2_PORTABILITY_EMPTY_TO_NULL) {
618
            $nullisempty = true;
619
        } else {
620
            $nullisempty = false;
621
        }
622
        $test_values = array(
623
            array('test', false),
624
            array('NULL', false),
625
            array('null', false),
626
            array('', $nullisempty),
627
            array(null, true)
628
        );
629
 
630
        for ($test_value = 0; $test_value <= count($test_values); $test_value++) {
631
            if ($test_value == count($test_values)) {
632
                $value = 'NULL';
633
                $is_null = true;
634
            } else {
635
                $value = $this->db->quote($test_values[$test_value][0], 'text');
636
                $is_null = $test_values[$test_value][1];
637
            }
638
 
639
            $this->clearTables();
640
 
641
            $result = $this->db->exec("INSERT INTO users (user_name,user_password,user_id) VALUES ($value,$value,0)");
642
 
643
            if (PEAR::isError($result)) {
644
                $this->assertTrue(false, 'Error executing insert query'.$result->getMessage());
645
            }
646
 
647
            $result =& $this->db->query('SELECT user_name,user_password FROM users', array('text', 'text'));
648
 
649
            if (PEAR::isError($result)) {
650
                $this->assertTrue(false, 'Error executing select query'.$result->getMessage());
651
            }
652
 
653
            if ($is_null) {
654
                $error_message = 'A query result column is not NULL unlike what was expected';
655
            } else {
656
                $error_message = 'A query result column is NULL even though it was expected to be differnt';
657
            }
658
 
659
            $row = $result->fetchRow();
660
            $this->assertTrue((is_null($row[0]) == $is_null), $error_message);
661
            $this->assertTrue((is_null($row[1]) == $is_null), $error_message);
662
 
663
            $result->free();
664
        }
665
 
666
        $methods = array('fetchOne', 'fetchRow');
667
 
668
        foreach ($methods as $method) {
669
            $result =& $this->db->query('SELECT user_name FROM users WHERE user_id=123', array('text'));
670
            $value = $result->$method();
671
            if (PEAR::isError($value)) {
672
                $this->assertTrue(false, 'Error fetching non existant row');
673
            } else {
674
                $this->assertNull($value, 'selecting non existant row with "'.$method.'()" did not return NULL');
675
                $result->free();
676
            }
677
        }
678
 
679
        $methods = array('fetchCol', 'fetchAll');
680
 
681
        foreach ($methods as $method) {
682
            $result =& $this->db->query('SELECT user_name FROM users WHERE user_id=123', array('text'));
683
            $value = $result->$method();
684
            if (PEAR::isError($value)) {
685
                $this->assertTrue(false, 'Error fetching non existant row');
686
            } else {
687
                $this->assertTrue((is_array($value) && empty($value)), 'selecting non existant row with "'.$method.'()" did not return empty array');
688
                $result->free();
689
            }
690
        }
691
 
692
        $methods = array('queryOne', 'queryRow');
693
 
694
        foreach ($methods as $method) {
695
            $value = $this->db->$method('SELECT user_name FROM users WHERE user_id=123', array('text'));
696
            if (PEAR::isError($value)) {
697
                $this->assertTrue(false, 'Error fetching non existant row');
698
            } else {
699
                $this->assertNull($value, 'selecting non existant row with "'.$method.'()" did not return NULL');
700
                $result->free();
701
            }
702
        }
703
 
704
        $methods = array('queryCol', 'queryAll');
705
 
706
        foreach ($methods as $method) {
707
            $value = $this->db->$method('SELECT user_name FROM users WHERE user_id=123', array('text'));
708
            if (PEAR::isError($value)) {
709
                $this->assertTrue(false, 'Error fetching non existant row');
710
            } else {
711
                $this->assertTrue((is_array($value) && empty($value)), 'selecting non existant row with "'.$method.'()" did not return empty array');
712
                $result->free();
713
            }
714
        }
715
    }
716
 
717
    /**
718
     * Test paged queries
719
     *
720
     * Test the use of setLimit to return paged queries
721
     */
722
    function testRanges() {
723
        if (!$this->supported('limit_queries')) {
724
            return;
725
        }
726
 
727
        $data = array();
728
        $total_rows = 5;
729
 
730
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
731
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
732
 
733
        for ($row = 0; $row < $total_rows; $row++) {
734
            $data[$row] = $this->getSampleData($row);
735
            $result = $stmt->execute(array_values($data[$row]));
736
 
737
            if (PEAR::isError($result)) {
738
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
739
            }
740
        }
741
 
742
        $stmt->free();
743
 
744
        for ($rows = 2, $start_row = 0; $start_row < $total_rows; $start_row += $rows) {
745
 
746
            $this->db->setLimit($rows, $start_row);
747
 
748
            $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name';
749
            $result =& $this->db->query($query, $this->fields);
750
 
751
            if (PEAR::isError($result)) {
752
                $this->assertTrue(false, 'Error executing select query'.$result->getMessage());
753
            }
754
 
755
            for ($row = 0; $row < $rows && ($row + $start_row < $total_rows); $row++) {
756
                $this->verifyFetchedValues($result, $row, $data[$row + $start_row]);
757
            }
758
        }
759
 
760
        $this->assertTrue(!$result->valid(), "The query result did not seem to have reached the end of result as expected starting row $start_row after fetching upto row $row");
761
 
762
        $result->free();
763
 
764
        for ($rows = 2, $start_row = 0; $start_row < $total_rows; $start_row += $rows) {
765
 
766
            $this->db->setLimit($rows, $start_row);
767
 
768
            $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name';
769
            $result =& $this->db->query($query, $this->fields);
770
 
771
            if (PEAR::isError($result)) {
772
                $this->assertTrue(false, 'Error executing select query'.$result->getMessage());
773
            }
774
 
775
            $result_rows = $result->numRows();
776
 
777
            $this->assertTrue(($result_rows <= $rows), 'expected a result of no more than '.$rows.' but the returned number of rows is '.$result_rows);
778
 
779
            for ($row = 0; $row < $result_rows; $row++) {
780
                $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result at row '.$row.' that is before '.$result_rows.' as expected');
781
 
782
                $this->verifyFetchedValues($result, $row, $data[$row + $start_row]);
783
            }
784
        }
785
 
786
        $this->assertTrue(!$result->valid(), "The query result did not seem to have reached the end of result as expected starting row $start_row after fetching upto row $row");
787
 
788
        $result->free();
789
    }
790
 
791
    /**
792
     * Test the handling of sequences
793
     */
794
    function testSequences() {
795
        if (!$this->supported('sequences')) {
796
           return;
797
        }
798
 
799
        $this->db->loadModule('Manager', null, true);
800
 
801
        for ($start_value = 1; $start_value < 4; $start_value++) {
802
            $sequence_name = "test_sequence_$start_value";
803
 
804
            $result = $this->db->manager->createSequence($sequence_name, $start_value);
805
            if (PEAR::isError($result)) {
806
                $this->assertTrue(false, "Error creating sequence $sequence_name with start value $start_value: ".$result->getMessage());
807
            } else {
808
                for ($sequence_value = $start_value; $sequence_value < ($start_value + 4); $sequence_value++) {
809
                    $value = $this->db->nextId($sequence_name, false);
810
 
811
                    $this->assertEquals($sequence_value, $value, "The returned sequence value is not expected with sequence start value with $start_value");
812
                }
813
 
814
                $result = $this->db->manager->dropSequence($sequence_name);
815
 
816
                if (PEAR::isError($result)) {
817
                    $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
818
                }
819
            }
820
        }
821
 
822
        // Test ondemand creation of sequences
823
        $sequence_name = 'test_ondemand';
824
        $this->db->expectError(MDB2_ERROR_NOSUCHTABLE);
825
        $this->db->manager->dropSequence($sequence_name);
826
        $this->db->popExpect();
827
 
828
        for ($sequence_value = 1; $sequence_value < 4; $sequence_value++) {
829
            $value = $this->db->nextId($sequence_name);
830
 
831
            if (PEAR::isError($result)) {
832
                $this->assertTrue(false, "Error creating with ondemand sequence: ".$result->getMessage());
833
            } else {
834
                $this->assertEquals($sequence_value, $value, "Error in ondemand sequences. The returned sequence value is not expected value");
835
            }
836
        }
837
 
838
        $result = $this->db->manager->dropSequence($sequence_name);
839
        if (PEAR::isError($result)) {
840
            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
841
        }
842
 
843
        // Test currId()
844
        $sequence_name = 'test_currid';
845
 
846
        $next = $this->db->nextId($sequence_name);
847
        $curr = $this->db->currId($sequence_name);
848
 
849
        if (PEAR::isError($curr)) {
850
            $this->assertTrue(false, "Error getting the current value of sequence $sequence_name : ".$curr->getMessage());
851
        } else {
852
            if ($next != $curr) {
853
                if ($next+1 == $curr) {
854
                    $this->assertTrue(false, "Warning: currId() is using nextId() instead of a native implementation");
855
                } else {
856
                    $this->assertEquals($next, $curr, "return value if currId() does not match the previous call to nextId()");
857
                }
858
            }
859
        }
860
        $result = $this->db->manager->dropSequence($sequence_name);
861
        if (PEAR::isError($result)) {
862
            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
863
        }
864
 
865
        // Test lastInsertid()
866
        if (!$this->supported('new_link')) {
867
           return;
868
        }
869
 
870
        $sequence_name = 'test_lastinsertid';
871
 
872
        $dsn = MDB2::parseDSN($this->dsn);
873
        $dsn['new_link'] = true;
874
        $dsn['database'] = $this->database;
875
        $db =& MDB2::connect($dsn, $this->options);
876
 
877
        $next = $this->db->nextId($sequence_name);
878
        $next2 = $db->nextId($sequence_name);
879
        $last = $this->db->lastInsertId($sequence_name);
880
 
881
        if (PEAR::isError($last)) {
882
            $this->assertTrue(false, "Error getting the last value of sequence $sequence_name : ".$last->getMessage());
883
        } else {
884
            $this->assertEquals($next, $last, "return value if lastInsertId() does not match the previous call to nextId()");
885
        }
886
        $result = $this->db->manager->dropSequence($sequence_name);
887
        if (PEAR::isError($result)) {
888
            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
889
        }
890
    }
891
 
892
    /**
893
     * Test replace query
894
     *
895
     * The replace method emulates the replace query of mysql
896
     */
897
    function testReplace() {
898
        if (!$this->supported('replace')) {
899
            return;
900
        }
901
 
902
        $row = 1234;
903
        $data = $this->getSampleData($row);
904
 
905
        $fields = array(
906
            'user_name' => array(
907
                'value' => "user_$row",
908
                'type' => 'text'
909
            ),
910
            'user_password' => array(
911
                'value' => $data['user_password'],
912
                'type' => 'text'
913
            ),
914
            'subscribed' => array(
915
                'value' => $data['subscribed'],
916
                'type' => 'boolean'
917
            ),
918
            'user_id' => array(
919
                'value' => $data['user_id'],
920
                'type' => 'integer',
921
                'key' => 1
922
            ),
923
            'quota' => array(
924
                'value' => $data['quota'],
925
                'type' => 'decimal'
926
            ),
927
            'weight' => array(
928
                'value' => $data['weight'],
929
                'type' => 'float'
930
            ),
931
            'access_date' => array(
932
                'value' => $data['access_date'],
933
                'type' => 'date'
934
            ),
935
            'access_time' => array(
936
                'value' => $data['access_time'],
937
                'type' => 'time'
938
            ),
939
            'approved' => array(
940
                'value' => $data['approved'],
941
                'type' => 'timestamp'
942
            )
943
        );
944
 
945
        $result = $this->db->replace('users', $fields);
946
 
947
        if (PEAR::isError($result)) {
948
            $this->assertTrue(false, 'Replace failed');
949
        }
950
 
951
        if ($this->db->supports('affected_rows')) {
952
            $affected_rows = $result;
953
 
954
            $this->assertEquals(1, $result, "replacing a row in an empty table returned incorrect value");
955
        } else {
956
            $this->assertTrue(false, '"affected_rows" is not supported');
957
        }
958
 
959
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
960
        $result =& $this->db->query($query, $this->fields);
961
 
962
        if (PEAR::isError($result)) {
963
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
964
        }
965
 
966
        $this->verifyFetchedValues($result, 0, $data);
967
 
968
        $row = 4321;
969
        $fields['user_name']['value']     = $data['user_name']     = 'user_'.$row;
970
        $fields['user_password']['value'] = $data['user_password'] = 'somepass';
971
        $fields['subscribed']['value']    = $data['subscribed']    = $row % 2 ? true : false;
972
        $fields['quota']['value']         = $data['quota']         = strval($row/100);
973
        $fields['weight']['value']        = $data['weight']        = sqrt($row);
974
        $fields['access_date']['value']   = $data['access_date']   = MDB2_Date::mdbToday();
975
        $fields['access_time']['value']   = $data['access_time']   = MDB2_Date::mdbTime();
976
        $fields['approved']['value']      = $data['approved']      = MDB2_Date::mdbNow();
977
 
978
        $result = $this->db->replace('users', $fields);
979
 
980
        if (PEAR::isError($result)) {
981
            $this->assertTrue(false, 'Replace failed');
982
        }
983
        if ($this->db->supports('affected_rows')) {
984
            $this->assertEquals(2, $result, "replacing a row returned incorrect result");
985
        }
986
 
987
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
988
        $result =& $this->db->query($query, $this->fields);
989
 
990
        if (PEAR::isError($result)) {
991
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
992
        }
993
 
994
        $this->verifyFetchedValues($result, 0, $data);
995
 
996
        $this->assertTrue(!$result->valid(), 'the query result did not seem to have reached the end of result as expected');
997
 
998
        $result->free();
999
    }
1000
 
1001
    /**
1002
     * Test affected rows methods
1003
     */
1004
    function testAffectedRows() {
1005
        if (!$this->supported('affected_rows')) {
1006
            return;
1007
        }
1008
 
1009
        $data = array();
1010
        $total_rows = 7;
1011
 
1012
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1013
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1014
 
1015
        for ($row = 0; $row < $total_rows; $row++) {
1016
            $data[$row] = $this->getSampleData($row);
1017
            $result = $stmt->execute(array_values($data[$row]));
1018
 
1019
            if (PEAR::isError($result)) {
1020
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
1021
            }
1022
 
1023
            $this->assertEquals(1, $result, "Inserting the row $row returned incorrect affected row count");
1024
        }
1025
 
1026
        $stmt->free();
1027
 
1028
        $query = 'UPDATE users SET user_password=? WHERE user_id < ?';
1029
        $stmt = $this->db->prepare($query, array('text', 'integer'), MDB2_PREPARE_MANIP);
1030
 
1031
        for ($row = 0; $row < $total_rows; $row++) {
1032
            $password = "pass_$row";
1033
            if ($row == 0) {
1034
                $stmt->bindParam(0, $password);
1035
                $stmt->bindParam(1, $row);
1036
            }
1037
 
1038
            $result = $stmt->execute();
1039
 
1040
            if (PEAR::isError($result)) {
1041
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
1042
            }
1043
 
1044
            $this->assertEquals($row, $result, "Updating the $row rows returned incorrect affected row count");
1045
        }
1046
 
1047
        $stmt->free();
1048
 
1049
        $query = 'DELETE FROM users WHERE user_id >= ?';
1050
        $stmt = $this->db->prepare($query, array('integer'), MDB2_PREPARE_MANIP);
1051
 
1052
        $row = intval($total_rows / 2);
1053
        $stmt->bindParam(0, $row);
1054
        for ($row = $total_rows; $total_rows; $total_rows = $row) {
1055
            $row = intval($total_rows / 2);
1056
 
1057
            $result = $stmt->execute();
1058
 
1059
            if (PEAR::isError($result)) {
1060
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
1061
            }
1062
 
1063
            $this->assertEquals(($total_rows - $row), $result, 'Deleting rows returned incorrect affected row count');
1064
 
1065
        }
1066
 
1067
        $stmt->free();
1068
    }
1069
 
1070
    /**
1071
     * Testing transaction support - Test ROLLBACK
1072
     */
1073
    function testTransactionsRollback() {
1074
        if (!$this->supported('transactions')) {
1075
            return;
1076
        }
1077
 
1078
        $data = $this->getSampleData(0);
1079
 
1080
        $this->db->beginTransaction();
1081
 
1082
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1083
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1084
 
1085
        $result = $stmt->execute(array_values($data));
1086
        $this->db->rollback();
1087
        $stmt->free();
1088
 
1089
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
1090
        $result =& $this->db->query($query);
1091
        if (PEAR::isError($result)) {
1092
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1093
        }
1094
        $this->assertTrue(!$result->valid(), 'Transaction rollback did not revert the row that was inserted');
1095
        $result->free();
1096
    }
1097
 
1098
    /**
1099
     * Testing transaction support - Test COMMIT
1100
     */
1101
    function testTransactionsCommit() {
1102
        if (!$this->supported('transactions')) {
1103
            return;
1104
        }
1105
 
1106
        $data = $this->getSampleData(1);
1107
 
1108
        $this->db->beginTransaction();
1109
 
1110
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1111
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1112
 
1113
        $result = $stmt->execute(array_values($data));
1114
        $this->db->commit();
1115
        $stmt->free();
1116
 
1117
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
1118
        $result =& $this->db->query($query);
1119
        if (PEAR::isError($result)) {
1120
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1121
        }
1122
        $this->assertTrue($result->valid(), 'Transaction commit did not make permanent the row that was inserted');
1123
        $result->free();
1124
    }
1125
 
1126
    /**
1127
     * Testing transaction support - Test COMMIT and ROLLBACK
1128
     */
1129
    function testTransactionsBoth()
1130
    {
1131
        if (!$this->supported('transactions')) {
1132
            return;
1133
        }
1134
 
1135
        $data = $this->getSampleData(0);
1136
 
1137
        $this->db->beginTransaction();
1138
        $result = $this->db->exec('DELETE FROM users');
1139
        if (PEAR::isError($result)) {
1140
            $this->assertTrue(false, 'Error deleting from users'.$result->getMessage());
1141
            $this->db->rollback();
1142
        } else {
1143
            $this->db->commit();
1144
        }
1145
 
1146
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
1147
        $result =& $this->db->query($query);
1148
        if (PEAR::isError($result)) {
1149
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1150
        }
1151
 
1152
        $this->assertTrue(!$result->valid(), 'Transaction end with implicit commit when re-enabling auto-commit did not make permanent the rows that were deleted');
1153
        $result->free();
1154
    }
1155
 
1156
    /**
1157
     * Testing emulated nested transaction support
1158
     */
1159
    function testNestedTransactions() {
1160
        if (!$this->supported('transactions')) {
1161
            return;
1162
        }
1163
 
1164
        $data = array(
1165
            1 => $this->getSampleData(1234),
1166
            2 => $this->getSampleData(4321),
1167
        );
1168
 
1169
        $this->db->beginNestedTransaction();
1170
 
1171
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1172
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1173
 
1174
        $result = $stmt->execute(array_values($data[1]));
1175
 
1176
        $this->db->beginNestedTransaction();
1177
 
1178
        $result = $stmt->execute(array_values($data[2]));
1179
        $stmt->free();
1180
 
1181
        $result = $this->db->completeNestedTransaction();
1182
        if (PEAR::isError($result)) {
1183
            $this->assertTrue(false, 'Inner transaction was not committed: '.$result->getMessage());
1184
        }
1185
 
1186
        $result = $this->db->completeNestedTransaction();
1187
        if (PEAR::isError($result)) {
1188
            $this->assertTrue(false, 'Outer transaction was not committed: '.$result->getMessage());
1189
        }
1190
 
1191
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
1192
        $result =& $this->db->query($query);
1193
        if (PEAR::isError($result)) {
1194
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1195
        }
1196
        $this->assertTrue($result->valid(), 'Transaction commit did not make permanent the row that was inserted');
1197
        $result->free();
1198
    }
1199
 
1200
    /**
1201
     * Testing savepoints
1202
     */
1203
    function testSavepoint() {
1204
        if (!$this->supported('savepoints')) {
1205
            return;
1206
        }
1207
 
1208
        $savepoint = 'test_savepoint';
1209
 
1210
        $data = array(
1211
            1 => $this->getSampleData(1234),
1212
            2 => $this->getSampleData(4321),
1213
        );
1214
 
1215
        $this->db->beginTransaction();
1216
 
1217
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1218
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1219
 
1220
        $result = $stmt->execute(array_values($data[1]));
1221
        if (PEAR::isError($result)) {
1222
            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
1223
        }
1224
 
1225
        $result = $this->db->beginTransaction($savepoint);
1226
        if (PEAR::isError($result)) {
1227
            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
1228
        }
1229
 
1230
        $result = $stmt->execute(array_values($data[2]));
1231
        if (PEAR::isError($result)) {
1232
            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
1233
        }
1234
        $stmt->free();
1235
 
1236
        $result = $this->db->rollback($savepoint);
1237
        if (PEAR::isError($result)) {
1238
            $this->assertTrue(false, 'Error rolling back to savepoint: '.$result->getMessage());
1239
        }
1240
 
1241
        $result = $this->db->commit();
1242
        if (PEAR::isError($result)) {
1243
            $this->assertTrue(false, 'Transaction not committed: '.$result->getMessage());
1244
        }
1245
 
1246
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
1247
        $result = $this->db->queryAll($query);
1248
        if (PEAR::isError($result)) {
1249
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1250
        }
1251
        $rows_inserted = count($result);
1252
        $this->assertEquals(1, $rows_inserted, 'Error during transaction, invalid number of records inserted');
1253
 
1254
        // test release savepoint
1255
        $this->db->beginTransaction();
1256
        $result = $this->db->beginTransaction($savepoint);
1257
        if (PEAR::isError($result)) {
1258
            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
1259
        }
1260
        $result = $this->db->commit($savepoint);
1261
        if (PEAR::isError($result)) {
1262
            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
1263
        }
1264
        $result = $this->db->commit();
1265
        if (PEAR::isError($result)) {
1266
            $this->assertTrue(false, 'Transaction not committed: '.$result->getMessage());
1267
        }
1268
    }
1269
 
1270
    /**
1271
     * Testing LOB storage
1272
     */
1273
    function testLOBStorage() {
1274
        if (!$this->supported('LOBs')) {
1275
            return;
1276
        }
1277
 
1278
        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
1279
        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
1280
 
1281
        $character_lob = '';
1282
        $binary_lob = '';
1283
 
1284
        for ($i = 0; $i < 1000; $i++) {
1285
            for ($code = 32; $code <= 127; $code++) {
1286
                $character_lob.= chr($code);
1287
            }
1288
            for ($code = 0; $code <= 255; $code++) {
1289
                $binary_lob.= chr($code);
1290
            }
1291
        }
1292
 
1293
        $stmt->bindParam(0, $character_lob);
1294
        $stmt->bindParam(1, $binary_lob);
1295
 
1296
        $result = $stmt->execute();
1297
 
1298
        if (PEAR::isError($result)) {
1299
            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
1300
        }
1301
 
1302
        $stmt->free();
1303
 
1304
        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
1305
        if (PEAR::isError($result)) {
1306
            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
1307
        }
1308
 
1309
        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
1310
 
1311
        $row = $result->fetchRow();
1312
        $clob = $row[0];
1313
        if (!PEAR::isError($clob) && is_resource($clob)) {
1314
            $value = '';
1315
            while (!feof($clob)) {
1316
                $data = fread($clob, 8192);
1317
                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
1318
                $value.= $data;
1319
            }
1320
            $this->db->datatype->destroyLOB($clob);
1321
            $this->assertEquals($character_lob, $value, 'Retrieved character LOB value is different from what was stored');
1322
        } else {
1323
            $this->assertTrue(false, 'Error retrieving CLOB result');
1324
        }
1325
 
1326
        $blob = $row[1];
1327
        if (!PEAR::isError($blob) && is_resource($blob)) {
1328
            $value = '';
1329
            while (!feof($blob)) {
1330
                $data = fread($blob, 8192);
1331
                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
1332
                $value.= $data;
1333
            }
1334
 
1335
            $this->db->datatype->destroyLOB($blob);
1336
            $this->assertEquals($binary_lob, $value, 'Retrieved binary LOB value is different from what was stored');
1337
        } else {
1338
            $this->assertTrue(false, 'Error retrieving BLOB result');
1339
        }
1340
        $result->free();
1341
    }
1342
 
1343
    /**
1344
     * Test LOB reading of multiple records both buffered and unbuffered. See bug #8793 for why this must be tested.
1345
     */
1346
    function testLOBRead() {
1347
        if (!$this->supported('LOBs')) {
1348
            return;
1349
        }
1350
 
1351
        for ($i = 20; $i < 30; ++$i) {
1352
            $query = 'INSERT INTO files (ID, document, picture) VALUES (?, ?, ?)';
1353
            $stmt = $this->db->prepare($query, array('integer', 'clob', 'blob'), MDB2_PREPARE_MANIP, array(1 => 'document', 2 => 'picture'));
1354
            $character_lob = $binary_lob = $i;
1355
            $stmt->bindParam(1, $character_lob);
1356
            $stmt->bindParam(2, $binary_lob);
1357
 
1358
            $result = $stmt->execute(array($i));
1359
 
1360
            if (PEAR::isError($result)) {
1361
                $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
1362
            }
1363
            $stmt->free();
1364
        }
1365
 
1366
        $oldBuffered = $this->db->getOption('result_buffering');
1367
        foreach (array(true, false) as $buffered) {
1368
            $this->db->setOption('result_buffering', $buffered);
1369
            $msgPost = ' with result_buffering = '.($buffered ? 'true' : 'false');
1370
            $result =& $this->db->query('SELECT id, document, picture FROM files WHERE id >= 20 and id <= 30 order by id asc', array('integer', 'clob', 'blob'));
1371
            if (PEAR::isError($result)) {
1372
                $this->assertTrue(false, 'Error selecting from files'.$msgPost.$result->getMessage());
1373
            } else {
1374
                if ($buffered) {
1375
                    $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon'.$msgPost);
1376
                }
1377
                for ($i = 1; $i <= ($buffered ? 2 : 1); ++$i) {
1378
                    $result->seek(0);
1379
                    while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
1380
                        foreach (array('document' => 'clob', 'picture' => 'blob') as $field => $type) {
1381
                            $lob = $row[$field];
1382
                            if (is_a($lob, 'oci-lob')) {
1383
                                $lob = $lob->load();
1384
                            } elseif (is_resource($lob)) {
1385
                                $lob = fread($lob, 1000);
1386
                            }
1387
                            $this->assertEquals($lob, $row['id'], 'LOB ('.$type.') field ('.$field.') not equal to expected value ('.$row['id'].')'.$msgPost.' on run-through '.$i);
1388
                        }
1389
                    }
1390
                }
1391
                $result->free();
1392
            }
1393
        }
1394
        $this->db->setOption('result_buffering', $oldBuffered);
1395
    }
1396
 
1397
    /**
1398
     * Test for lob storage from and to files
1399
     */
1400
    function testLOBFiles() {
1401
        if (!$this->supported('LOBs')) {
1402
            return;
1403
        }
1404
 
1405
        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, :document, :picture)';
1406
        $stmt = $this->db->prepare($query, array('document' => 'clob', 'picture' => 'blob'), MDB2_PREPARE_MANIP);
1407
 
1408
        $character_data_file = 'character_data';
1409
        $file = fopen($character_data_file, 'w');
1410
        $this->assertTrue(((bool)$file), 'Error creating clob file to read from');
1411
        $character_data = '';
1412
        for ($i = 0; $i < 1000; $i++) {
1413
            for ($code = 32; $code <= 127; $code++) {
1414
                $character_data.= chr($code);
1415
            }
1416
        }
1417
        $this->assertTrue((fwrite($file, $character_data, strlen($character_data)) == strlen($character_data)), 'Error creating clob file to read from');
1418
        fclose($file);
1419
 
1420
        $binary_data_file = 'binary_data';
1421
        $file = fopen($binary_data_file, 'wb');
1422
        $this->assertTrue(((bool)$file), 'Error creating blob file to read from');
1423
        $binary_data = '';
1424
        for ($i = 0; $i < 1000; $i++) {
1425
            for ($code = 0; $code <= 255; $code++) {
1426
                $binary_data.= chr($code);
1427
            }
1428
        }
1429
        $this->assertTrue((fwrite($file, $binary_data, strlen($binary_data)) == strlen($binary_data)), 'Error creating blob file to read from');
1430
        fclose($file);
1431
 
1432
        $character_data_file_tmp = 'file://'.$character_data_file;
1433
        $stmt->bindParam('document', $character_data_file_tmp);
1434
        $binary_data_file_tmp = 'file://'.$binary_data_file;
1435
        $stmt->bindParam('picture', $binary_data_file_tmp);
1436
 
1437
        $result = $stmt->execute();
1438
        $this->assertTrue(!PEAR::isError($result), 'Error executing prepared query - inserting LOB from files');
1439
 
1440
        $stmt->free();
1441
 
1442
        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
1443
        if (PEAR::isError($result)) {
1444
            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
1445
        }
1446
 
1447
        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
1448
 
1449
        $row = $result->fetchRow();
1450
        $clob = $row[0];
1451
        if (!PEAR::isError($clob) && is_resource($clob)) {
1452
            unlink($character_data_file);
1453
            $res = $this->db->datatype->writeLOBToFile($clob, $character_data_file);
1454
            $this->db->datatype->destroyLOB($clob);
1455
 
1456
            if (PEAR::isError($res)) {
1457
                $this->assertTrue(false, 'Error writing character LOB in a file');
1458
            } else {
1459
                $file = fopen($character_data_file, 'r');
1460
                $this->assertTrue($file, "Error opening character data file: $character_data_file");
1461
                $value = '';
1462
                while (!feof($file)) {
1463
                    $value.= fread($file, 8192);
1464
                }
1465
                $this->assertEquals('string', gettype($value), "Could not read from character LOB file: $character_data_file");
1466
                fclose($file);
1467
 
1468
                $this->assertEquals($character_data, $value, "retrieved character LOB value is different from what was stored");
1469
            }
1470
        } else {
1471
            $this->assertTrue(false, 'Error creating character LOB in a file');
1472
        }
1473
 
1474
        $blob = $row[1];
1475
        if (!PEAR::isError($blob) && is_resource($blob)) {
1476
            unlink($binary_data_file);
1477
            $res = $this->db->datatype->writeLOBToFile($blob, $binary_data_file);
1478
            $this->db->datatype->destroyLOB($blob);
1479
 
1480
            if (PEAR::isError($res)) {
1481
                $this->assertTrue(false, 'Error writing binary LOB in a file');
1482
            } else {
1483
                $file = fopen($binary_data_file, 'rb');
1484
                $this->assertTrue($file, "Error opening binary data file: $binary_data_file");
1485
                $value = '';
1486
                while (!feof($file)) {
1487
                    $value.= fread($file, 8192);
1488
                }
1489
                $this->assertEquals('string', gettype($value), "Could not read from binary LOB file: $binary_data_file");
1490
                fclose($file);
1491
 
1492
                $this->assertEquals($binary_data, $value, "retrieved binary LOB value is different from what was stored");
1493
            }
1494
        } else {
1495
            $this->assertTrue(false, 'Error creating binary LOB in a file');
1496
        }
1497
 
1498
        $result->free();
1499
    }
1500
 
1501
    /**
1502
     * Test handling of lob nulls
1503
     */
1504
    function testLOBNulls() {
1505
        if (!$this->supported('LOBs')) {
1506
            return;
1507
        }
1508
 
1509
        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, :document, :picture)';
1510
        $stmt = $this->db->prepare($query, array('document' => 'clob', 'picture' => 'blob'), MDB2_PREPARE_MANIP);
1511
 
1512
        $null = null;
1513
        $stmt->bindParam('document', $null);
1514
        $stmt->bindParam('picture', $null);
1515
 
1516
        $result = $stmt->execute();
1517
        $this->assertTrue(!PEAR::isError($result), 'Error executing prepared query - inserting NULL lobs');
1518
 
1519
        $stmt->free();
1520
 
1521
        $result =& $this->db->query('SELECT document, picture FROM files', array('clob', 'blob'));
1522
        if (PEAR::isError($result)) {
1523
            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
1524
        }
1525
 
1526
        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
1527
 
1528
        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
1529
        $this->assertTrue(is_null($row['document']), 'A query result large object column document is not NULL unlike what was expected');
1530
        $this->assertTrue(is_null($row['picture']), 'A query result large object column picture is not NULL unlike what was expected');
1531
 
1532
        $result->free();
1533
    }
1534
 
1535
    function testLOBUpdate() {
1536
        if (!$this->supported('LOBs')) {
1537
            return;
1538
        }
1539
 
1540
        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
1541
        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
1542
 
1543
        $character_lob = '';
1544
        $binary_lob = '';
1545
 
1546
        for ($i = 0; $i < 1000; $i++) {
1547
            for ($code = 32; $code <= 127; ++$code) {
1548
                $character_lob .= chr($code);
1549
            }
1550
            for ($code = 0; $code <= 255; ++$code) {
1551
                $binary_lob .= chr($code);
1552
            }
1553
        }
1554
 
1555
        $stmt->bindParam(0, $character_lob);
1556
        $stmt->bindParam(1, $binary_lob);
1557
 
1558
        $result = $stmt->execute();
1559
 
1560
        if (PEAR::isError($result)) {
1561
            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
1562
        }
1563
 
1564
        $stmt->free();
1565
 
1566
        $query = 'UPDATE files SET document = ?, picture = ? WHERE ID = 1';
1567
        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
1568
 
1569
        $character_lob = '';
1570
        $binary_lob = '';
1571
 
1572
        for ($i = 0; $i < 999; $i++) {
1573
            for ($code = 127; $code >= 32; --$code) {
1574
                $character_lob .= chr($code);
1575
            }
1576
            for ($code = 255; $code >= 0; --$code) {
1577
                $binary_lob .= chr($code);
1578
            }
1579
        }
1580
 
1581
        $stmt->bindParam(0, $character_lob);
1582
        $stmt->bindParam(1, $binary_lob);
1583
 
1584
        $result = $stmt->execute();
1585
 
1586
        if (PEAR::isError($result)) {
1587
            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
1588
        }
1589
 
1590
        $stmt->free();
1591
 
1592
        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
1593
        if (PEAR::isError($result)) {
1594
            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
1595
        }
1596
 
1597
        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
1598
 
1599
        $row = $result->fetchRow();
1600
        $clob = $row[0];
1601
        if (!PEAR::isError($clob) && is_resource($clob)) {
1602
            $value = '';
1603
            while (!feof($clob)) {
1604
                $data = fread($clob, 8192);
1605
                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
1606
                $value.= $data;
1607
            }
1608
            $this->db->datatype->destroyLOB($clob);
1609
            $this->assertEquals($character_lob, $value, 'Retrieved character LOB value is different from what was stored');
1610
        } else {
1611
            $this->assertTrue(false, 'Error retrieving CLOB result');
1612
        }
1613
 
1614
        $blob = $row[1];
1615
        if (!PEAR::isError($blob) && is_resource($blob)) {
1616
            $value = '';
1617
            while (!feof($blob)) {
1618
                $data = fread($blob, 8192);
1619
                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
1620
                $value.= $data;
1621
            }
1622
 
1623
            $this->db->datatype->destroyLOB($blob);
1624
            $this->assertEquals($binary_lob, $value, 'Retrieved binary LOB value is different from what was stored');
1625
        } else {
1626
            $this->assertTrue(false, 'Error retrieving BLOB result');
1627
        }
1628
        $result->free();
1629
    }
1630
 
1631
    /**
1632
     * Test retrieval of result metadata
1633
     *
1634
     * This tests the result metadata by executing a prepared query and
1635
     * select the data, and checking the result contains the correct
1636
     * number of columns and that the column names are in the correct order
1637
     */
1638
    function testConvertEmpty2Null() {
1639
#$this->db->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL);
1640
 
1641
        $data = $this->getSampleData(1234);
1642
        $data['user_password'] = '';
1643
 
1644
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1645
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1646
        $result = $stmt->execute(array_values($data));
1647
        $stmt->free();
1648
 
1649
        if (PEAR::isError($result)) {
1650
            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
1651
        }
1652
 
1653
        $row = $this->db->queryRow('SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users WHERE user_password IS NULL', $this->fields);
1654
 
1655
        if (PEAR::isError($row)) {
1656
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1657
        }
1658
 
1659
        $this->assertEquals(count($this->fields), count($row), "The query result returned a number of columns unlike ".count($this->fields) .' as expected');
1660
    }
1661
 
1662
    function testPortabilityOptions() {
1663
        // MDB2_PORTABILITY_DELETE_COUNT
1664
        $data = array();
1665
        $total_rows = 5;
1666
 
1667
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1668
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1669
        for ($row = 0; $row < $total_rows; $row++) {
1670
            $data[$row] = $this->getSampleData($row);
1671
            $result = $stmt->execute(array_values($data[$row]));
1672
            if (PEAR::isError($result)) {
1673
                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
1674
            }
1675
        }
1676
        $stmt->free();
1677
 
1678
        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_DELETE_COUNT);
1679
        $affected_rows = $this->db->exec('DELETE FROM users');
1680
        if (PEAR::isError($affected_rows)) {
1681
            $this->assertTrue(false, 'Error executing query'.$affected_rows->getMessage());
1682
        }
1683
        $this->assertEquals($total_rows, $affected_rows, 'MDB2_PORTABILITY_DELETE_COUNT not working');
1684
 
1685
        // MDB2_PORTABILITY_FIX_CASE
1686
        $fields = array_keys($this->fields);
1687
        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_FIX_CASE);
1688
        $this->db->setOption('field_case', CASE_UPPER);
1689
 
1690
        $data = $this->getSampleData(1234);
1691
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1692
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1693
        $result = $stmt->execute(array_values($data));
1694
        $stmt->free();
1695
 
1696
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
1697
        $result =& $this->db->queryRow($query, $this->fields, MDB2_FETCHMODE_ASSOC);
1698
        if (PEAR::isError($result)) {
1699
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1700
        }
1701
        $field = reset($fields);
1702
        foreach (array_keys($result) as $fieldname) {
1703
            $this->assertEquals(strtoupper($field), $fieldname, 'MDB2_PORTABILITY_FIX_CASE CASE_UPPER not working');
1704
            $field = next($fields);
1705
        }
1706
 
1707
        $this->db->setOption('field_case', CASE_LOWER);
1708
        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
1709
        $result =& $this->db->queryRow($query, $this->fields, MDB2_FETCHMODE_ASSOC);
1710
        if (PEAR::isError($result)) {
1711
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1712
        }
1713
        $field = reset($fields);
1714
        foreach (array_keys($result) as $fieldname) {
1715
            $this->assertEquals(strtolower($field), $fieldname, 'MDB2_PORTABILITY_FIX_CASE CASE_LOWER not working');
1716
            $field = next($fields);
1717
        }
1718
 
1719
        // MDB2_PORTABILITY_RTRIM
1720
        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_RTRIM);
1721
        $value = 'rtrim   ';
1722
        $query = 'INSERT INTO users (user_id, user_password) VALUES (1, ' . $this->db->quote($value, 'text') .')';
1723
        $res = $this->db->exec($query);
1724
        if (PEAR::isError($res)) {
1725
            $this->assertTrue(false, 'Error executing query'.$res->getMessage());
1726
        }
1727
        $query = 'SELECT user_password FROM users WHERE user_id = 1';
1728
        $result = $this->db->queryOne($query, array('text'));
1729
        if (PEAR::isError($result)) {
1730
            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
1731
        }
1732
        $this->assertEquals(rtrim($value), $result, '"MDB2_PORTABILITY_RTRIM = on" not working');
1733
 
1734
        if (!$this->supported('LOBs')) {
1735
            return;
1736
        }
1737
 
1738
        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
1739
        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
1740
 
1741
        $character_lob = '';
1742
        $binary_lob = '';
1743
 
1744
        for ($i = 0; $i < 999; $i++) {
1745
            for ($code = 127; $code >= 32; --$code) {
1746
                $character_lob .= chr($code);
1747
            }
1748
            for ($code = 255; $code >= 0; --$code) {
1749
                $binary_lob .= chr($code);
1750
            }
1751
        }
1752
 
1753
        $stmt->bindParam(0, $character_lob);
1754
        $stmt->bindParam(1, $binary_lob);
1755
 
1756
        $result = $stmt->execute();
1757
 
1758
        if (PEAR::isError($result)) {
1759
            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
1760
        }
1761
 
1762
        $stmt->free();
1763
 
1764
        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
1765
        if (PEAR::isError($result)) {
1766
            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
1767
        }
1768
 
1769
        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
1770
 
1771
        $row = $result->fetchRow();
1772
        $clob = $row[0];
1773
        if (!PEAR::isError($clob) && is_resource($clob)) {
1774
            $value = '';
1775
            while (!feof($clob)) {
1776
                $data = fread($clob, 8192);
1777
                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
1778
                $value.= $data;
1779
            }
1780
            $this->db->datatype->destroyLOB($clob);
1781
            $this->assertEquals($character_lob, $value, '"MDB2_PORTABILITY_RTRIM = on" Retrieved character LOB value is different from what was stored');
1782
        } else {
1783
            $this->assertTrue(false, 'Error retrieving CLOB result');
1784
        }
1785
 
1786
        $blob = $row[1];
1787
        if (!PEAR::isError($blob) && is_resource($blob)) {
1788
            $value = '';
1789
            while (!feof($blob)) {
1790
                $data = fread($blob, 8192);
1791
                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
1792
                $value.= $data;
1793
            }
1794
 
1795
            $this->db->datatype->destroyLOB($blob);
1796
            $this->assertEquals($binary_lob, $value, '"MDB2_PORTABILITY_RTRIM = on" Retrieved binary LOB value is different from what was stored');
1797
        } else {
1798
            $this->assertTrue(false, 'Error retrieving BLOB result');
1799
        }
1800
        $result->free();
1801
    }
1802
 
1803
    /**
1804
     * Test getAsKeyword()
1805
     */
1806
    function testgetAsKeyword()
1807
    {
1808
        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
1809
        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
1810
        $data = $this->getSampleData(1);
1811
        $result = $stmt->execute(array_values($data));
1812
        if (PEAR::isError($result)) {
1813
            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
1814
        }
1815
        $stmt->free();
1816
 
1817
        $query = 'SELECT user_id'.$this->db->getAsKeyword().'foo FROM users';
1818
        $result = $this->db->queryRow($query, array('integer'), MDB2_FETCHMODE_ASSOC);
1819
        if (PEAR::isError($result)) {
1820
            $this->assertFalse(true, 'Error getting alias column:'. $result->getMessage());
1821
        } else {
1822
            $this->assertTrue((array_key_exists('foo', $result)), 'Error: could not alias "user_id" with "foo" :'.var_export($result, true));
1823
        }
1824
    }
1825
}
1826
 
1827
?>