~ubuntu-branches/ubuntu/trusty/fusionforge/trusty

« back to all changes in this revision

Viewing changes to plugins/wiki/www/lib/pear/DB/fbsql.php

  • Committer: Bazaar Package Importer
  • Author(s): Roland Mas
  • Date: 2011-04-15 14:55:34 UTC
  • mfrom: (4.1.10 sid)
  • Revision ID: james.westby@ubuntu.com-20110415145534-mvn1nochufjmw177
Tags: 5.0.3-1
New upstream bugfix release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
 
3
// +----------------------------------------------------------------------+
 
4
// | PHP Version 4                                                        |
 
5
// +----------------------------------------------------------------------+
 
6
// | Copyright (c) 1997-2004 The PHP Group                                |
 
7
// +----------------------------------------------------------------------+
 
8
// | This source file is subject to version 2.02 of the PHP license,      |
 
9
// | that is bundled with this package in the file LICENSE, and is        |
 
10
// | available at through the world-wide-web at                           |
 
11
// | http://www.php.net/license/2_02.txt.                                 |
 
12
// | If you did not receive a copy of the PHP license and are unable to   |
 
13
// | obtain it through the world-wide-web, please send a note to          |
 
14
// | license@php.net so we can mail you a copy immediately.               |
 
15
// +----------------------------------------------------------------------+
 
16
// | Author: Frank M. Kromann <frank@frontbase.com>                       |
 
17
// | Maintainer: Daniel Convissor <danielc@php.net>                       |
 
18
// +----------------------------------------------------------------------+
 
19
//
 
20
// $Id: fbsql.php 6184 2008-08-22 10:33:41Z vargenau $
 
21
 
 
22
 
 
23
// XXX legend:
 
24
//
 
25
// XXX ERRORMSG: The error message from the fbsql function should
 
26
//               be registered here.
 
27
//
 
28
// TODO/wishlist:
 
29
// longReadlen
 
30
// binmode
 
31
 
 
32
 
 
33
require_once 'DB/common.php';
 
34
 
 
35
/**
 
36
 * Database independent query interface definition for PHP's FrontBase
 
37
 * extension.
 
38
 *
 
39
 * @package  DB
 
40
 * @version  $Id: fbsql.php 6184 2008-08-22 10:33:41Z vargenau $
 
41
 * @category Database
 
42
 * @author   Frank M. Kromann <frank@frontbase.com>
 
43
 */
 
44
class DB_fbsql extends DB_common
 
45
{
 
46
    // {{{ properties
 
47
 
 
48
    var $connection;
 
49
    var $phptype, $dbsyntax;
 
50
    var $prepare_tokens = array();
 
51
    var $prepare_types = array();
 
52
    var $num_rows = array();
 
53
    var $fetchmode = DB_FETCHMODE_ORDERED; /* Default fetch mode */
 
54
 
 
55
    // }}}
 
56
    // {{{ constructor
 
57
 
 
58
    /**
 
59
     * DB_fbsql constructor.
 
60
     *
 
61
     * @access public
 
62
     */
 
63
    function DB_fbsql()
 
64
    {
 
65
        $this->DB_common();
 
66
        $this->phptype = 'fbsql';
 
67
        $this->dbsyntax = 'fbsql';
 
68
        $this->features = array(
 
69
            'prepare' => false,
 
70
            'pconnect' => true,
 
71
            'transactions' => true,
 
72
            'limit' => 'emulate'
 
73
        );
 
74
        $this->errorcode_map = array(
 
75
            1004 => DB_ERROR_CANNOT_CREATE,
 
76
            1005 => DB_ERROR_CANNOT_CREATE,
 
77
            1006 => DB_ERROR_CANNOT_CREATE,
 
78
            1007 => DB_ERROR_ALREADY_EXISTS,
 
79
            1008 => DB_ERROR_CANNOT_DROP,
 
80
            1046 => DB_ERROR_NODBSELECTED,
 
81
            1050 => DB_ERROR_ALREADY_EXISTS,
 
82
            1051 => DB_ERROR_NOSUCHTABLE,
 
83
            1054 => DB_ERROR_NOSUCHFIELD,
 
84
            1062 => DB_ERROR_ALREADY_EXISTS,
 
85
            1064 => DB_ERROR_SYNTAX,
 
86
            1100 => DB_ERROR_NOT_LOCKED,
 
87
            1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
 
88
            1146 => DB_ERROR_NOSUCHTABLE,
 
89
        );
 
90
    }
 
91
 
 
92
    // }}}
 
93
    // {{{ connect()
 
94
 
 
95
    /**
 
96
     * Connect to a database and log in as the specified user.
 
97
     *
 
98
     * @param $dsn the data source name (see DB::parseDSN for syntax)
 
99
     * @param $persistent (optional) whether the connection should
 
100
     *        be persistent
 
101
     * @access public
 
102
     * @return int DB_OK on success, a DB error on failure
 
103
     */
 
104
    function connect($dsninfo, $persistent = false)
 
105
    {
 
106
        if (!DB::assertExtension('fbsql')) {
 
107
            return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
 
108
        }
 
109
 
 
110
        $this->dsn = $dsninfo;
 
111
        $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
 
112
 
 
113
        $php_errormsg = '';
 
114
        $connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect';
 
115
 
 
116
        if ($dbhost && $dsninfo['username'] && $dsninfo['password']) {
 
117
            $conn = @$connect_function($dbhost, $dsninfo['username'],
 
118
                                       $dsninfo['password']);
 
119
        } elseif ($dbhost && $dsninfo['username']) {
 
120
            $conn = @$connect_function($dbhost, $dsninfo['username']);
 
121
        } elseif ($dbhost) {
 
122
            $conn = @$connect_function($dbhost);
 
123
        } else {
 
124
            $conn = false;
 
125
        }
 
126
        if (!$conn) {
 
127
            if (empty($php_errormsg)) {
 
128
                return $this->raiseError(DB_ERROR_CONNECT_FAILED);
 
129
            } else {
 
130
                return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
 
131
                                         null, $php_errormsg);
 
132
            }
 
133
        }
 
134
 
 
135
        if ($dsninfo['database']) {
 
136
            if (!fbsql_select_db($dsninfo['database'], $conn)) {
 
137
                return $this->fbsqlRaiseError();
 
138
            }
 
139
        }
 
140
 
 
141
        $this->connection = $conn;
 
142
        return DB_OK;
 
143
    }
 
144
 
 
145
    // }}}
 
146
    // {{{ disconnect()
 
147
 
 
148
    /**
 
149
     * Log out and disconnect from the database.
 
150
     *
 
151
     * @access public
 
152
     *
 
153
     * @return bool true on success, false if not connected.
 
154
     */
 
155
    function disconnect()
 
156
    {
 
157
        $ret = @fbsql_close($this->connection);
 
158
        $this->connection = null;
 
159
        return $ret;
 
160
    }
 
161
 
 
162
    // }}}
 
163
    // {{{ simpleQuery()
 
164
 
 
165
    /**
 
166
     * Send a query to fbsql and return the results as a fbsql resource
 
167
     * identifier.
 
168
     *
 
169
     * @param the SQL query
 
170
     *
 
171
     * @access public
 
172
     *
 
173
     * @return mixed returns a valid fbsql result for successful SELECT
 
174
     * queries, DB_OK for other successful queries.  A DB error is
 
175
     * returned on failure.
 
176
     */
 
177
    function simpleQuery($query)
 
178
    {
 
179
        $this->last_query = $query;
 
180
        $query = $this->modifyQuery($query);
 
181
        $result = @fbsql_query("$query;", $this->connection);
 
182
        if (!$result) {
 
183
            return $this->fbsqlRaiseError();
 
184
        }
 
185
        // Determine which queries that should return data, and which
 
186
        // should return an error code only.
 
187
        if (DB::isManip($query)) {
 
188
            return DB_OK;
 
189
        }
 
190
        $numrows = $this->numrows($result);
 
191
        if (is_object($numrows)) {
 
192
            return $numrows;
 
193
        }
 
194
        $this->num_rows[$result] = $numrows;
 
195
        return $result;
 
196
    }
 
197
 
 
198
    // }}}
 
199
    // {{{ nextResult()
 
200
 
 
201
    /**
 
202
     * Move the internal fbsql result pointer to the next available result
 
203
     *
 
204
     * @param a valid fbsql result resource
 
205
     *
 
206
     * @access public
 
207
     *
 
208
     * @return true if a result is available otherwise return false
 
209
     */
 
210
    function nextResult($result)
 
211
    {
 
212
        return @fbsql_next_result($result);
 
213
    }
 
214
 
 
215
    // }}}
 
216
    // {{{ fetchInto()
 
217
 
 
218
    /**
 
219
     * Fetch a row and insert the data into an existing array.
 
220
     *
 
221
     * Formating of the array and the data therein are configurable.
 
222
     * See DB_result::fetchInto() for more information.
 
223
     *
 
224
     * @param resource $result    query result identifier
 
225
     * @param array    $arr       (reference) array where data from the row
 
226
     *                            should be placed
 
227
     * @param int      $fetchmode how the resulting array should be indexed
 
228
     * @param int      $rownum    the row number to fetch
 
229
     *
 
230
     * @return mixed DB_OK on success, null when end of result set is
 
231
     *               reached or on failure
 
232
     *
 
233
     * @see DB_result::fetchInto()
 
234
     * @access private
 
235
     */
 
236
    function fetchInto($result, &$arr, $fetchmode, $rownum=null)
 
237
    {
 
238
        if ($rownum !== null) {
 
239
            if (!@fbsql_data_seek($result, $rownum)) {
 
240
                return null;
 
241
            }
 
242
        }
 
243
        if ($fetchmode & DB_FETCHMODE_ASSOC) {
 
244
            $arr = @fbsql_fetch_array($result, FBSQL_ASSOC);
 
245
            if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
 
246
                $arr = array_change_key_case($arr, CASE_LOWER);
 
247
            }
 
248
        } else {
 
249
            $arr = @fbsql_fetch_row($result);
 
250
        }
 
251
        if (!$arr) {
 
252
            $errno = @fbsql_errno($this->connection);
 
253
            if (!$errno) {
 
254
                return null;
 
255
            }
 
256
            return $this->fbsqlRaiseError($errno);
 
257
        }
 
258
        if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
 
259
            $this->_rtrimArrayValues($arr);
 
260
        }
 
261
        if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
 
262
            $this->_convertNullArrayValuesToEmpty($arr);
 
263
        }
 
264
        return DB_OK;
 
265
    }
 
266
 
 
267
    // }}}
 
268
    // {{{ freeResult()
 
269
 
 
270
    /**
 
271
     * Free the internal resources associated with $result.
 
272
     *
 
273
     * @param $result fbsql result identifier
 
274
     *
 
275
     * @access public
 
276
     *
 
277
     * @return bool true on success, false if $result is invalid
 
278
     */
 
279
    function freeResult($result)
 
280
    {
 
281
        return @fbsql_free_result($result);
 
282
    }
 
283
 
 
284
    // }}}
 
285
    // {{{ autoCommit()
 
286
 
 
287
    function autoCommit($onoff=false)
 
288
    {
 
289
        if ($onoff) {
 
290
            $this->query("SET COMMIT TRUE");
 
291
        } else {
 
292
            $this->query("SET COMMIT FALSE");
 
293
        }
 
294
    }
 
295
 
 
296
    // }}}
 
297
    // {{{ commit()
 
298
 
 
299
    function commit()
 
300
    {
 
301
        @fbsql_commit();
 
302
    }
 
303
 
 
304
    // }}}
 
305
    // {{{ rollback()
 
306
 
 
307
    function rollback()
 
308
    {
 
309
        @fbsql_rollback();
 
310
    }
 
311
 
 
312
    // }}}
 
313
    // {{{ numCols()
 
314
 
 
315
    /**
 
316
     * Get the number of columns in a result set.
 
317
     *
 
318
     * @param $result fbsql result identifier
 
319
     *
 
320
     * @access public
 
321
     *
 
322
     * @return int the number of columns per row in $result
 
323
     */
 
324
    function numCols($result)
 
325
    {
 
326
        $cols = @fbsql_num_fields($result);
 
327
 
 
328
        if (!$cols) {
 
329
            return $this->fbsqlRaiseError();
 
330
        }
 
331
 
 
332
        return $cols;
 
333
    }
 
334
 
 
335
    // }}}
 
336
    // {{{ numRows()
 
337
 
 
338
    /**
 
339
     * Get the number of rows in a result set.
 
340
     *
 
341
     * @param $result fbsql result identifier
 
342
     *
 
343
     * @access public
 
344
     *
 
345
     * @return int the number of rows in $result
 
346
     */
 
347
    function numRows($result)
 
348
    {
 
349
        $rows = @fbsql_num_rows($result);
 
350
        if ($rows === null) {
 
351
            return $this->fbsqlRaiseError();
 
352
        }
 
353
        return $rows;
 
354
    }
 
355
 
 
356
    // }}}
 
357
    // {{{ affectedRows()
 
358
 
 
359
    /**
 
360
     * Gets the number of rows affected by the data manipulation
 
361
     * query.  For other queries, this function returns 0.
 
362
     *
 
363
     * @return number of rows affected by the last query
 
364
     */
 
365
    function affectedRows()
 
366
    {
 
367
        if (DB::isManip($this->last_query)) {
 
368
            $result = @fbsql_affected_rows($this->connection);
 
369
        } else {
 
370
            $result = 0;
 
371
        }
 
372
        return $result;
 
373
     }
 
374
 
 
375
    // }}}
 
376
    // {{{ errorNative()
 
377
 
 
378
    /**
 
379
     * Get the native error code of the last error (if any) that
 
380
     * occured on the current connection.
 
381
     *
 
382
     * @access public
 
383
     *
 
384
     * @return int native fbsql error code
 
385
     */
 
386
    function errorNative()
 
387
    {
 
388
        return @fbsql_errno($this->connection);
 
389
    }
 
390
 
 
391
    // }}}
 
392
    // {{{ nextId()
 
393
 
 
394
    /**
 
395
     * Returns the next free id in a sequence
 
396
     *
 
397
     * @param string  $seq_name  name of the sequence
 
398
     * @param boolean $ondemand  when true, the seqence is automatically
 
399
     *                           created if it does not exist
 
400
     *
 
401
     * @return int  the next id number in the sequence.  DB_Error if problem.
 
402
     *
 
403
     * @internal
 
404
     * @see DB_common::nextID()
 
405
     * @access public
 
406
     */
 
407
    function nextId($seq_name, $ondemand = true)
 
408
    {
 
409
        $seqname = $this->getSequenceName($seq_name);
 
410
        $repeat = 0;
 
411
        do {
 
412
            $result = $this->query("INSERT INTO ${seqname} VALUES(NULL)");
 
413
            if ($ondemand && DB::isError($result) &&
 
414
                $result->getCode() == DB_ERROR_NOSUCHTABLE) {
 
415
                $repeat = 1;
 
416
                $result = $this->createSequence($seq_name);
 
417
                if (DB::isError($result)) {
 
418
                    return $result;
 
419
                }
 
420
            } else {
 
421
                $repeat = 0;
 
422
            }
 
423
        } while ($repeat);
 
424
        if (DB::isError($result)) {
 
425
            return $result;
 
426
        }
 
427
        return @fbsql_insert_id($this->connection);
 
428
    }
 
429
 
 
430
    /**
 
431
     * Creates a new sequence
 
432
     *
 
433
     * @param string $seq_name  name of the new sequence
 
434
     *
 
435
     * @return int  DB_OK on success.  A DB_Error object is returned if
 
436
     *              problems arise.
 
437
     *
 
438
     * @internal
 
439
     * @see DB_common::createSequence()
 
440
     * @access public
 
441
     */
 
442
    function createSequence($seq_name)
 
443
    {
 
444
        $seqname = $this->getSequenceName($seq_name);
 
445
        return $this->query("CREATE TABLE ${seqname} ".
 
446
                            '(id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'.
 
447
                            ' PRIMARY KEY(id))');
 
448
    }
 
449
 
 
450
    // }}}
 
451
    // {{{ dropSequence()
 
452
 
 
453
    /**
 
454
     * Deletes a sequence
 
455
     *
 
456
     * @param string $seq_name  name of the sequence to be deleted
 
457
     *
 
458
     * @return int  DB_OK on success.  DB_Error if problems.
 
459
     *
 
460
     * @internal
 
461
     * @see DB_common::dropSequence()
 
462
     * @access public
 
463
     */
 
464
    function dropSequence($seq_name)
 
465
    {
 
466
        $seqname = $this->getSequenceName($seq_name);
 
467
        return $this->query("DROP TABLE ${seqname} RESTRICT");
 
468
    }
 
469
 
 
470
    // }}}
 
471
    // {{{ modifyQuery()
 
472
 
 
473
    function modifyQuery($query)
 
474
    {
 
475
        if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
 
476
            // "DELETE FROM table" gives 0 affected rows in fbsql.
 
477
            // This little hack lets you know how many rows were deleted.
 
478
            if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
 
479
                $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
 
480
                                      'DELETE FROM \1 WHERE 1=1', $query);
 
481
            }
 
482
        }
 
483
        return $query;
 
484
    }
 
485
 
 
486
    // }}}
 
487
    // {{{ quoteSmart()
 
488
 
 
489
    /**
 
490
     * Format input so it can be safely used in a query
 
491
     *
 
492
     * @param mixed $in  data to be quoted
 
493
     *
 
494
     * @return mixed Submitted variable's type = returned value:
 
495
     *               + null = the string <samp>NULL</samp>
 
496
     *               + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
 
497
     *               + integer or double = the unquoted number
 
498
     *               + other (including strings and numeric strings) =
 
499
     *                 the data escaped according to MySQL's settings
 
500
     *                 then encapsulated between single quotes
 
501
     *
 
502
     * @internal
 
503
     */
 
504
    function quoteSmart($in)
 
505
    {
 
506
        if (is_int($in) || is_double($in)) {
 
507
            return $in;
 
508
        } elseif (is_bool($in)) {
 
509
            return $in ? 'TRUE' : 'FALSE';
 
510
        } elseif (is_null($in)) {
 
511
            return 'NULL';
 
512
        } else {
 
513
            return "'" . $this->escapeSimple($in) . "'";
 
514
        }
 
515
    }
 
516
 
 
517
    // }}}
 
518
    // {{{ fbsqlRaiseError()
 
519
 
 
520
    /**
 
521
     * Gather information about an error, then use that info to create a
 
522
     * DB error object and finally return that object.
 
523
     *
 
524
     * @param  integer  $errno  PEAR error number (usually a DB constant) if
 
525
     *                          manually raising an error
 
526
     * @return object  DB error object
 
527
     * @see DB_common::errorCode()
 
528
     * @see DB_common::raiseError()
 
529
     */
 
530
    function fbsqlRaiseError($errno = null)
 
531
    {
 
532
        if ($errno === null) {
 
533
            $errno = $this->errorCode(fbsql_errno($this->connection));
 
534
        }
 
535
        return $this->raiseError($errno, null, null, null,
 
536
                        @fbsql_error($this->connection));
 
537
    }
 
538
 
 
539
    // }}}
 
540
    // {{{ tableInfo()
 
541
 
 
542
    /**
 
543
     * Returns information about a table or a result set.
 
544
     *
 
545
     * @param object|string  $result  DB_result object from a query or a
 
546
     *                                string containing the name of a table
 
547
     * @param int            $mode    a valid tableInfo mode
 
548
     * @return array  an associative array with the information requested
 
549
     *                or an error object if something is wrong
 
550
     * @access public
 
551
     * @internal
 
552
     * @see DB_common::tableInfo()
 
553
     */
 
554
    function tableInfo($result, $mode = null) {
 
555
        if (isset($result->result)) {
 
556
            /*
 
557
             * Probably received a result object.
 
558
             * Extract the result resource identifier.
 
559
             */
 
560
            $id = $result->result;
 
561
            $got_string = false;
 
562
        } elseif (is_string($result)) {
 
563
            /*
 
564
             * Probably received a table name.
 
565
             * Create a result resource identifier.
 
566
             */
 
567
            $id = @fbsql_list_fields($this->dsn['database'],
 
568
                                     $result, $this->connection);
 
569
            $got_string = true;
 
570
        } else {
 
571
            /*
 
572
             * Probably received a result resource identifier.
 
573
             * Copy it.
 
574
             * Depricated.  Here for compatibility only.
 
575
             */
 
576
            $id = $result;
 
577
            $got_string = false;
 
578
        }
 
579
 
 
580
        if (!is_resource($id)) {
 
581
            return $this->fbsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
 
582
        }
 
583
 
 
584
        if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
 
585
            $case_func = 'strtolower';
 
586
        } else {
 
587
            $case_func = 'strval';
 
588
        }
 
589
 
 
590
        $count = @fbsql_num_fields($id);
 
591
 
 
592
        // made this IF due to performance (one if is faster than $count if's)
 
593
        if (!$mode) {
 
594
            for ($i=0; $i<$count; $i++) {
 
595
                $res[$i]['table'] = $case_func(@fbsql_field_table($id, $i));
 
596
                $res[$i]['name']  = $case_func(@fbsql_field_name($id, $i));
 
597
                $res[$i]['type']  = @fbsql_field_type($id, $i);
 
598
                $res[$i]['len']   = @fbsql_field_len($id, $i);
 
599
                $res[$i]['flags'] = @fbsql_field_flags($id, $i);
 
600
            }
 
601
        } else { // full
 
602
            $res["num_fields"]= $count;
 
603
 
 
604
            for ($i=0; $i<$count; $i++) {
 
605
                $res[$i]['table'] = $case_func(@fbsql_field_table($id, $i));
 
606
                $res[$i]['name']  = $case_func(@fbsql_field_name($id, $i));
 
607
                $res[$i]['type']  = @fbsql_field_type($id, $i);
 
608
                $res[$i]['len']   = @fbsql_field_len($id, $i);
 
609
                $res[$i]['flags'] = @fbsql_field_flags($id, $i);
 
610
 
 
611
                if ($mode & DB_TABLEINFO_ORDER) {
 
612
                    $res['order'][$res[$i]['name']] = $i;
 
613
                }
 
614
                if ($mode & DB_TABLEINFO_ORDERTABLE) {
 
615
                    $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
 
616
                }
 
617
            }
 
618
        }
 
619
 
 
620
        // free the result only if we were called on a table
 
621
        if ($got_string) {
 
622
            @fbsql_free_result($id);
 
623
        }
 
624
        return $res;
 
625
    }
 
626
 
 
627
    // }}}
 
628
    // {{{ getSpecialQuery()
 
629
 
 
630
    /**
 
631
     * Returns the query needed to get some backend info
 
632
     * @param string $type What kind of info you want to retrieve
 
633
     * @return string The SQL query string
 
634
     */
 
635
    function getSpecialQuery($type)
 
636
    {
 
637
        switch ($type) {
 
638
            case 'tables':
 
639
                return 'select "table_name" from information_schema.tables';
 
640
            default:
 
641
                return null;
 
642
        }
 
643
    }
 
644
 
 
645
    // }}}
 
646
}
 
647
 
 
648
/*
 
649
 * Local variables:
 
650
 * tab-width: 4
 
651
 * c-basic-offset: 4
 
652
 * End:
 
653
 */
 
654
 
 
655
?>