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 Version 4                                                        |
4
// +----------------------------------------------------------------------+
5
// | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
6
// | Stig. S. Bakken, Lukas Smith                                         |
7
// | All rights reserved.                                                 |
8
// +----------------------------------------------------------------------+
9
// | MDB is a merge of PEAR DB and Metabases that provides a unified DB   |
10
// | API as well as database abstraction for PHP applications.            |
11
// | This LICENSE is in the BSD license style.                            |
12
// |                                                                      |
13
// | Redistribution and use in source and binary forms, with or without   |
14
// | modification, are permitted provided that the following conditions   |
15
// | are met:                                                             |
16
// |                                                                      |
17
// | Redistributions of source code must retain the above copyright       |
18
// | notice, this list of conditions and the following disclaimer.        |
19
// |                                                                      |
20
// | Redistributions in binary form must reproduce the above copyright    |
21
// | notice, this list of conditions and the following disclaimer in the  |
22
// | documentation and/or other materials provided with the distribution. |
23
// |                                                                      |
24
// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
25
// | Lukas Smith nor the names of his contributors may be used to endorse |
26
// | or promote products derived from this software without specific prior|
27
// | written permission.                                                  |
28
// |                                                                      |
29
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
30
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
31
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
32
// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
33
// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
34
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
35
// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
36
// |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
37
// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
38
// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
39
// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
40
// | POSSIBILITY OF SUCH DAMAGE.                                          |
41
// +----------------------------------------------------------------------+
42
// | Original QuerySim Concept & ColdFusion Author: Hal Helms             |
43
// | <hal.helms@teamallaire.com>                                          |
44
// | Bert Dawson <bdawson@redbanner.com>                                  |
45
// +----------------------------------------------------------------------+
46
// | Original PHP Author: Alan Richmond <arichmond@bigfoot.com>           |
47
// | David Huyck <b@bombusbee.com>                                        |
48
// +----------------------------------------------------------------------+
49
// | Special note concerning code documentation:                          |
50
// | QuerySim was originally created for use during development of        |
51
// | applications built using the Fusebox framework. (www.fusebox.org)    |
52
// | Fusebox uses an XML style of documentation called Fusedoc. (Which    |
53
// | is admittedly not well suited to documenting classes and functions.  |
54
// | This short-coming is being addressed by the Fusebox community.) PEAR |
55
// | uses a Javadoc style of documentation called PHPDoc. (www.phpdoc.de) |
56
// | Since this class extension spans two groups of users, it is asked    |
57
// | that the members of each respect the documentation standard of the   |
58
// | other.  So it is a further requirement that both documentation       |
59
// | standards be included and maintained. If assistance is required      |
60
// | please contact Alan Richmond.                                        |
61
// +----------------------------------------------------------------------+
62
//
63
// $Id: querysim.php,v 1.6.4.5 2004/02/26 11:51:15 lsmith Exp $
64
//
65
 
66
/*
67
<fusedoc fuse="querysim.php" language="PHP">
68
    <responsibilities>
69
        I take information and turn it into a recordset that can be accessed
70
        through the PEAR MDB API.  Based on Hal Helms' QuerySim.cfm ColdFusion
71
        custom tag available at halhelms.com.
72
    </responsibilities>
73
    <properties>
74
        <property name="API" value="PEAR MDB" />
75
        <property name="version" value="0.2.1" />
76
        <property name="status" value="beta" />
77
        <history author="Hal Helms" email="hal.helms@teamallaire.com" type="Create" />
78
        <history author="Bert Dawson" email="bdawson@redbanner.com" type="Update">
79
            Extensive revision that is backwardly compatible but eliminates the
80
            need for a separate .sim file.
81
        </history>
82
        <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Create" date="10-July-2002">
83
            Rewrote in PHP as an extention to the PEAR DB API.
84
            Functions supported:
85
                connect, disconnect, query, fetchRow, fetchInto, freeResult,
86
                numCols, numRows, getSpecialQuery
87
            David Huyck (bombusbee.com) added ability to escape special
88
                characters (i.e., delimiters) using a '\'.
89
            Extended PEAR DB options[] for adding incoming parameters.  Added
90
                options:  columnDelim, dataDelim, eolDelim
91
        </history>
92
        <history author="David Huyck" email="b@bombusbee.com" type="Update" date="19-July-2002">
93
            Added the ability to set the QuerySim options at runtime.
94
            Default options are:
95
                'columnDelim' => ',',            // Commas split the column names
96
                'dataDelim'   => '|',            // Pipes split the data fields
97
                'eolDelim'    => chr(13).chr(10) // Carriage returns split the
98
                                                 // lines of data
99
            Affected functions are:
100
                DB_querysim():          set the default options when the
101
                                        constructor method is called
102
                _parseQuerySim($query): altered the parsing of lines, column
103
                                        names, and data fields
104
                _empty2null:            altered the way this function is called
105
                                        to simplify calling it
106
        </history>
107
        <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="24-July-2002">
108
            Added error catching for malformed QuerySim text.
109
            Bug fix _empty2null():  altered version was returning unmodified
110
                                    lineData.
111
            Cleanup:
112
                PEAR compliant formatting, finished PHPDocs and added 'out' to
113
                Fusedoc 'io'.
114
                Broke up _parseQuerySim() into _buildResult() and _parseOnDelim()
115
                to containerize duplicate parse code.
116
        </history>
117
        <history author="David Huyck" email="b@bombusbee.com" type="Update" date="25-July-2002">
118
            Edited the _buildResult() and _parseOnDelim() functions to improve
119
            reliability of special character escaping.
120
            Re-introduced a custom setOption() method to throw an error when a
121
            person tries to set one of the delimiters to '\'.
122
        </history>
123
        <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="27-July-2002">
124
            Added '/' delimiter param to preg_quote() in _empty2null() and
125
            _parseOnDelim() so '/' can be used as a delimiter.
126
            Added error check for columnDelim == eolDelim or dataDelim == eolDelim.
127
            Renamed some variables for consistancy.
128
        </history>
129
        <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="30-July-2002">
130
            Removed private function _empty2null().  Turns out preg_split()
131
            deals with empty elemants by making them zero length strings, just
132
            what they ended up being anyway.  This should speed things up a little.
133
            Affected functions:
134
                _parseOnDelim()     perform trim on line here, instead of in
135
                                    _empty2null().
136
                _buildResult()      remove call to _empty2null().
137
                _empty2null()       removed function.
138
        </history>
139
        <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="1-Jan-2003">
140
            Ported to PEAR MDB.
141
            Methods supported:
142
                connect, query, getColumnNames, numCols, endOfResult, fetch,
143
                numRows, freeResult, fetchInto, nextResult, setSelectedRowRange
144
                (inherited).
145
        </history>
146
        <history
147
            Removed array_change_key_case() work around for <4.2.0 in
148
            getColumnNames(), found it already done in MDB/Common.php.
149
        </history>
150
        <history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="3-Feb-2003">
151
            Changed default eolDelim to a *nix file eol, since we're trimming
152
            the result anyway, it makes no difference for Windows.  Now only
153
            Mac file eols should need to be set (and other kinds of chars).
154
        </history>
155
        <note author="Alan Richmond">
156
            Got WAY too long.  See querysim_readme.txt for instructions and some
157
            examples.
158
            io section only documents elements of DB_result that DB_querysim uses,
159
            adds or changes; see MDB and MDB_Common for more info.
160
            io section uses some elements that are not Fusedoc 2.0 compliant:
161
            object and resource.
162
        </note>
163
    </properties>
164
    <io>
165
        <in>
166
            <file path="MDB/Common.php" action="require_once" />
167
        </in>
168
        <out>
169
            <object name="MDB_querysim" extends="MDB_Common" instantiatedby="MDB::connect()">
170
                <resource type="file" name="connection" oncondition="source is external file" scope="class" />
171
                <string name="phptype" default="querysim" />
172
                <string name="dbsyntax" default="querysim" />
173
                <array name="supported" comments="most of these don't actually do anything, they are enabled to simulate the option being available if checked">
174
                    <boolean name="Sequences" default="true" />
175
                    <boolean name="Indexes" default="true" />
176
                    <boolean name="AffectedRows" default="true" />
177
                    <boolean name="Summaryfunctions" default="true" />
178
                    <boolean name="OrderByText" default="true" />
179
                    <boolean name="CurrId" default="true" />
180
                    <boolean name="SelectRowRanges" default="true" comments="this one is functional" />
181
                    <boolean name="LOBs" default="true" />
182
                    <boolean name="Replace" default="true" />
183
                    <boolean name="SubSelects" default="true" />
184
                    <boolean name="Transactions" default="true" />
185
                </array>
186
                <string name="last_query" comments="last value passed in with query()" />
187
                <array name="options" comments="these can be changed at run time">
188
                    <string name="columnDelim" default="," />
189
                    <string name="dataDelim" default="|" />
190
                    <string name="eolDelim" default="chr(13).chr(10)" />
191
                </array>
192
            </object>
193
            <array name="result" comments="the simulated record set returned by ::query()">
194
                <array comments="columns">
195
                    <string comments="column name" />
196
                </array>
197
                <array comments="data">
198
                    <array comments="row">
199
                        <string comments="data element" />
200
                    </array>
201
                </array>
202
            </array>
203
        </out>
204
    </io>
205
</fusedoc>
206
*/
207
 
208
require_once 'MDB/Common.php';
209
 
210
/**
211
 * MDB QuerySim driver
212
 *
213
 * @package MDB
214
 * @category Database
215
 * @author  Alan Richmond <arichmond@bigfoot.com>
216
 */
217
class MDB_querysim extends MDB_Common
218
{
219
// Most of the class variables are taken from the corresponding Metabase driver.
220
// Few are taken from the corresponding PEAR DB driver.
221
// Some are MDB specific.
222
    var $connection = 0;
223
    var $connected_host;
224
    var $connected_user;
225
    var $connected_password;
226
    var $connected_port;
227
    var $opened_persistent = '';
228
 
229
    var $escape_quotes = "\\";
230
    var $decimal_factor = 1.0;
231
 
232
    var $highest_fetched_row = array();
233
    var $columns = array();
234
    // }}}
235
 
236
    // {{{ constructor
237
 
238
    /**
239
    * Constructor
240
    */
241
    function MDB_querysim()
242
    {
243
        $this->MDB_Common();
244
        $this->phptype  = 'querysim';
245
        $this->dbsyntax = 'querysim';
246
 
247
        // Most of these are dummies to simulate availability if checked
248
        $this->supported['Sequences'] = 1;
249
        $this->supported['Indexes'] = 1;
250
        $this->supported['AffectedRows'] = 1;
251
        $this->supported['Summaryfunctions'] = 1;
252
        $this->supported['OrderByText'] = 1;
253
        $this->supported['CurrId'] = 1;
254
        $this->supported['SelectRowRanges'] = 1;// this one is real
255
        $this->supported['LOBs'] = 1;
256
        $this->supported['Replace'] = 1;
257
        $this->supported['SubSelects'] = 1;
258
        $this->supported['Transactions'] = 1;
259
 
260
        // init QuerySim options
261
        $querySimOptions = array(
262
            'columnDelim' => ',',
263
            'dataDelim'   => '|',
264
            'eolDelim'    => "\n"
265
        );
266
        // let runtime options overwrite defaults
267
        $this->options = array_merge($querySimOptions, $this->options);
268
    }
269
    // }}}
270
 
271
    // {{{ connect()
272
 
273
    /**
274
     * Open a file or simulate a successful database connect
275
     *
276
     * @param string $dsn the data source name (see MDB::parseDSN for syntax)
277
     * @param mixed $persistent (optional) boolean whether the connection should
278
     *        be persistent (default FALSE) or assoc array of config options
279
     *
280
     * @access public
281
     *
282
     * @return mixed MDB_OK string on success, a MDB error object on failure
283
     */
284
    function connect()
285
    {
286
        if($this->connection != 0) {
287
            if (!strcmp($this->selected_database, $this->database_name)
288
                && ($this->opened_persistent == $this->options['persistent']))
289
            {
290
                return MDB_OK;
291
            }
292
            if ($this->selected_database) {
293
                $this->_close($this->connection);
294
            }
295
            $this->connection = 0;
296
        }
297
        if(is_array($this->options)) {
298
            foreach($this->options as $option => $value) {
299
                if((in_array($option, array('columnDelim','dataDelim','eolDelim')))
300
                    && ($value == '\\')) {
301
                        return $this->raiseError(MDB_ERROR, null, null,
302
                            "MDB Error: option $option cannot be set to '\\'");
303
                }
304
            }
305
        }
306
        $connection = 1;// sim connect
307
        // if external, check file...
308
        if ($this->database_name) {
309
            $file = $this->database_name;
310
            if (!file_exists($file)) {
311
                return $this->raiseError(MDB_ERROR_NOT_FOUND, null, null, 'file not found');
312
            }
313
            if (!is_file($file)) {
314
                return $this->raiseError(MDB_ERROR_INVALID, null, null, 'not a file');
315
            }
316
            if (!is_readable($file)) {
317
                return $this->raiseError(MDB_ERROR_ACCESS_VIOLATION, null, null,
318
                    'could not open file - check permissions');
319
            }
320
            // ...and open if persistent
321
            if ($this->options['persistent']) {
322
                $connection = @fopen($file, 'r');
323
            }
324
        }
325
        $this->connection = $connection;
326
        $this->selected_database = $this->database_name;
327
        $this->opened_persistent = $this->options['persistent'];
328
        return MDB_OK;
329
    }
330
    // }}}
331
 
332
    // {{{ _close()
333
 
334
    /**
335
     * Close a file or simulate a successful database disconnect
336
     *
337
     * @access public
338
     *
339
     * @return bool TRUE on success, FALSE if file closed.
340
     *              Always TRUE if simulated.
341
     */
342
    function _close()
343
    {
344
        $ret = true;
345
        if ($this->connection != 0) {
346
            if (($this->opened_persistent) && (is_resource($this->connection))) {
347
                echo 'closed file';
348
                $ret = @fclose($this->connection);
349
            }
350
            $this->connection = 0;
351
            unset($GLOBALS['_MDB_databases'][$this->database]);
352
        }
353
        return $ret;
354
    }
355
    // }}}
356
 
357
    // {{{ setOption()
358
 
359
    /**
360
    * Set the option for the MDB class
361
    *
362
    * @param string $option option name
363
    * @param mixed  $value value for the option
364
    *
365
    * @return mixed MDB_OK or MDB_Error
366
    */
367
    function setOption($option, $value)
368
    {
369
        if ((in_array($option, array('columnDelim','dataDelim','eolDelim')))
370
            && ($value == '\\')
371
        ) {
372
            return $this->raiseError("option $option cannot be set to '\\'");
373
        }
374
        if (isset($this->options[$option])) {
375
            $this->options[$option] = $value;
376
            return MDB_OK;
377
        }
378
        return $this->raiseError("unknown option $option");
379
    }
380
    // }}}
381
 
382
    // {{{ query()
383
 
384
    /**
385
     * Get QuerySim text from appropriate source and return
386
     * the parsed text.
387
     *
388
     * @param string The QuerySim text
389
     * @param mixed   $types  array that contains the types of the columns in
390
     *                        the result set
391
     *
392
     * @access public
393
     *
394
     * @return mixed Simulated result set as a multidimentional
395
     * array if valid QuerySim text was passed in.  A MDB error
396
     * is returned on failure.
397
     */
398
    function query($query, $types = null)
399
    {
400
        if ($this->database_name) {
401
            $query = $this->_readFile();
402
        }
403
 
404
        $this->debug("Query: $query");
405
        $ismanip = false;
406
 
407
        $first = $this->first_selected_row;
408
        $limit = $this->selected_row_limit;
409
        $this->last_query = $query;
410
 
411
        if ($result = $this->_buildResult($query)) {
412
            if ($types != null) {
413
                if (!is_array($types)) {
414
                    $types = array($types);
415
                }
416
                if (MDB::isError($err = $this->setResultTypes($result, $types))) {
417
                    $this->freeResult($result);
418
                    return $err;
419
                }
420
            }
421
            if ($limit > 0) {
422
                $result[1] = array_slice($result[1], $first-1, $limit);
423
            }
424
            $this->highest_fetched_row[$this->_querySimSignature($result)] = -1;
425
 
426
            return $result;
427
        }
428
        return $this->raiseError();
429
    }
430
 
431
    // }}}
432
 
433
    // {{{ _readFile()
434
 
435
    /**
436
     * Read an external file
437
     *
438
     * @param string filepath/filename
439
     *
440
     * @access private
441
     *
442
     * @return string the contents of a file
443
     */
444
    function _readFile()
445
    {
446
        $buffer = '';
447
        if ($this->opened_persistent) {
448
            while (!feof($this->connection)) {
449
                $buffer .= fgets($this->connection, 1024);
450
            }
451
        } else {
452
            $this->connection = @fopen($this->selected_database, 'r');
453
            while (!feof($this->connection)) {
454
                $buffer .= fgets($this->connection, 1024);
455
            }
456
            $this->connection = @fclose($this->connection);
457
        }
458
        return $buffer;
459
    }
460
    // }}}
461
 
462
    // {{{ _buildResult()
463
 
464
    /**
465
     * Convert QuerySim text into an array
466
     *
467
     * @param string Text of simulated query
468
     *
469
     * @access private
470
     *
471
     * @return multi-dimensional array containing the column names and data
472
     *                                 from the QuerySim
473
     */
474
    function _buildResult($query)
475
    {
476
        $eolDelim    = $this->options['eolDelim'];
477
        $columnDelim = $this->options['columnDelim'];
478
        $dataDelim   = $this->options['dataDelim'];
479
 
480
        $columnNames = array();
481
        $data        = array();
482
 
483
        if ($columnDelim == $eolDelim) {
484
            return $this->raiseError(MDB_ERROR_INVALID, null, null,
485
                'columnDelim and eolDelim must be different');
486
        } elseif ($dataDelim == $eolDelim){
487
            return $this->raiseError(MDB_ERROR_INVALID, null, null,
488
                'dataDelim and eolDelim must be different');
489
        }
490
 
491
        $query = trim($query);
492
        //tokenize escaped slashes
493
        $query = str_replace('\\\\', '[$double-slash$]', $query);
494
 
495
        if (!strlen($query)) {
496
            return $this->raiseError(MDB_ERROR_SYNTAX, null, null,
497
                'empty querysim text');
498
        }
499
        $lineData = $this->_parseOnDelim($query, $eolDelim);
500
        //kill the empty last row created by final eol char if it exists
501
        if (!strlen(trim($lineData[count($lineData) - 1]))) {
502
            unset($lineData[count($lineData) - 1]);
503
        }
504
        //populate columnNames array
505
        $thisLine = each($lineData);
506
        $columnNames = $this->_parseOnDelim($thisLine[1], $columnDelim);
507
        if ((in_array('', $columnNames)) || (in_array('null', $columnNames))) {
508
            return $this->raiseError(MDB_ERROR_SYNTAX, null, null,
509
                'all column names must be defined');
510
        }
511
        //replace double-slash tokens with single-slash
512
        $columnNames = str_replace('[$double-slash$]', '\\', $columnNames);
513
        $columnCount = count($columnNames);
514
        $rowNum = 0;
515
        //loop through data lines
516
        if (count($lineData) > 1) {
517
            while ($thisLine = each($lineData)) {
518
                $thisData = $this->_parseOnDelim($thisLine[1], $dataDelim);
519
                $thisDataCount = count($thisData);
520
                if ($thisDataCount != $columnCount) {
521
                    $fileLineNo = $rowNum + 2;
522
                    return $this->raiseError(MDB_ERROR_SYNTAX, null, null,
523
                        "number of data elements ($thisDataCount) in line $fileLineNo not equal to number of defined columns ($columnCount)");
524
                }
525
                //loop through data elements in data line
526
                foreach ($thisData as $thisElement) {
527
                    if (strtolower($thisElement) == 'null'){
528
                        $thisElement = '';
529
                    }
530
                    //replace double-slash tokens with single-slash
531
                    $data[$rowNum][] = str_replace('[$double-slash$]', '\\', $thisElement);
532
                }//end foreach
533
                ++$rowNum;
534
            }//end while
535
        }//end if
536
        return array($columnNames, $data);
537
    }//end function _buildResult()
538
    // }}}
539
 
540
    // {{{ _parseOnDelim()
541
 
542
    /**
543
     * Split QuerySim string into an array on a delimiter
544
     *
545
     * @param string $thisLine Text of simulated query
546
     * @param string $delim    The delimiter to split on
547
     *
548
     * @access private
549
     *
550
     * @return array containing parsed string
551
     */
552
    function _parseOnDelim($thisLine, $delim)
553
    {
554
        $delimQuoted = preg_quote($delim, '/');
555
        $thisLine = trim($thisLine);
556
 
557
        $parsed = preg_split('/(?<!\\\\)' .$delimQuoted. '/', $thisLine);
558
        //replaces escaped delimiters
559
        $parsed = preg_replace('/\\\\' .$delimQuoted. '/', $delim, $parsed);
560
        if ($delim != $this->options['eolDelim']) {
561
            //replaces escape chars
562
            $parsed = preg_replace('/\\\\/', '', $parsed);
563
        }
564
        return $parsed;
565
    }
566
    // }}}
567
 
568
    // {{{ _querySimSignature()
569
 
570
    /**
571
     * Creates a signature for the QuerySim.
572
     * This is a work-around for not having a resultset resource handle to ref.
573
     *
574
     * @access private
575
     *
576
     * @param array $result the array of QuerySim results
577
     *
578
     * @return string the signature
579
     */
580
    function _querySimSignature($result)
581
    {
582
        // convert array to string and get hash.
583
        // hash is used to keep length down.
584
        $sig = md5(serialize($result));
585
        return $sig;
586
    }
587
    // }}}
588
 
589
    // {{{ getColumnNames()
590
 
591
    /**
592
     * Retrieve the names of columns returned by the DBMS in a query result.
593
     *
594
     * @param resource   $result    result identifier
595
     * @return mixed                an associative array variable
596
     *                              that will hold the names of columns. The
597
     *                              indexes of the array are the column names
598
     *                              mapped to lower case and the values are the
599
     *                              respective numbers of the columns starting
600
     *                              from 0. Some DBMS may not return any
601
     *                              columns when the result set does not
602
     *                              contain any rows.
603
     *
604
     *                              a MDB error on failure
605
     * @access public
606
     */
607
    function getColumnNames($result)
608
    {
609
        $result_value = $this->_querySimSignature($result);
610
        if (!isset($this->highest_fetched_row[$result_value])) {
611
            return($this->raiseError(MDB_ERROR, NULL, NULL,
612
                'Get column names: it was specified an inexisting result set'));
613
        }
614
        if (!isset($this->columns[$result_value])) {
615
            $this->columns[$result_value] = array();
616
            $columns = array_flip($result[0]);
617
            if ($this->options['optimize'] == 'portability') {
618
                $columns = array_change_key_case($columns, CASE_LOWER);
619
            }
620
            $this->columns[$result_value] = $columns;
621
        }
622
        return($this->columns[$result_value]);
623
    }
624
    // }}}
625
 
626
    // {{{ numCols()
627
 
628
    /**
629
     * Count the number of columns returned by the DBMS in a query result.
630
     *
631
     * @param resource    $result        result identifier
632
     * @access public
633
     * @return mixed integer value with the number of columns, a MDB error
634
     *                       on failure
635
     */
636
    function numCols($result)
637
    {
638
        $result_value = $this->_querySimSignature($result);
639
        if (!isset($this->highest_fetched_row[$result_value])) {
640
            return $this->raiseError(MDB_ERROR_INVALID, null, null,
641
                'numCols: a non-existant result set was specified');
642
        }
643
        $cols = count($result[0]);
644
        return $cols;
645
    }
646
    // }}}
647
 
648
    // {{{ endOfResult()
649
 
650
    /**
651
    * check if the end of the result set has been reached
652
    *
653
    * @param resource    $result result identifier
654
    * @return mixed TRUE or FALSE on sucess, a MDB error on failure
655
    * @access public
656
    */
657
    function endOfResult($result)
658
    {
659
        $result_value = $this->_querySimSignature($result);
660
        if (!isset($this->highest_fetched_row[$result_value])) {
661
            return $this->raiseError(MDB_ERROR, null, null,
662
                'endOfResult(): attempted to check the end of an unknown result');
663
        }
664
        return ($this->highest_fetched_row[$result_value] >= $this->numRows($result)-1);
665
    }
666
    // }}}
667
 
668
    // {{{ fetch()
669
 
670
    /**
671
    * fetch value from a simulated result set
672
    *
673
    * @param array  $result simulated result
674
    * @param int    $row    number of the row where the data can be found
675
    * @param int    $field    field number where the data can be found
676
    * @return mixed string on success, a MDB error on failure
677
    * @access public
678
    */
679
    function fetch($result, $row, $field)
680
    {
681
        $result_value = $this->_querySimSignature($result);
682
        $this->highest_fetched_row[$result_value] = max($this->highest_fetched_row[$result_value], $row);
683
        if (isset($result[1][$row][$field])) {
684
            $res = $result[1][$row][$field];
685
        } else {
686
            return $this->raiseError(MDB_ERROR, null, null,
687
                "fetch():  row $row, field $field is undefined in result set");
688
        }
689
        return $res;
690
    }
691
    // }}}
692
 
693
    // {{{ numRows()
694
 
695
    /**
696
    * returns the number of rows in a result object
697
    *
698
     * @param ressource $result a valid result ressouce pointer
699
    * @return mixed MDB_Error or the number of rows
700
    * @access public
701
    */
702
    function numRows($result)
703
    {
704
        $result_value = $this->_querySimSignature($result);
705
        if (!isset($this->highest_fetched_row[$result_value])) {
706
            return $this->raiseError(MDB_ERROR_INVALID, null, null,
707
                'numRows(): a non-existant result set was specified');
708
        }
709
        $rows = @count($result[1]);
710
        return $rows;
711
    }
712
    // }}}
713
 
714
    // {{{ freeResult()
715
 
716
    /**
717
     * Free the internal resources associated with $result.
718
     *
719
     * @param $result result identifier
720
     * @return bool TRUE on success, FALSE if $result is invalid
721
     * @access public
722
     */
723
    function freeResult(&$result)
724
    {
725
        $result_value = $this->_querySimSignature($result);
726
 
727
        if(isset($this->highest_fetched_row[$result_value])) {
728
            unset($this->highest_fetched_row[$result_value]);
729
        }
730
        if(isset($this->columns[$result_value])) {
731
            unset($this->columns[$result_value]);
732
        }
733
        if(isset($this->result_types[$result_value])) {
734
            unset($this->result_types[$result_value]);
735
        }
736
        if (isset($result)) {
737
            // can't unset() in caller, so this is the best we can do...
738
            $result = null;
739
        } else {
740
            return false;
741
        }
742
        return true;
743
    }
744
    // }}}
745
 
746
    // {{{ fetchInto()
747
 
748
    /**
749
     * Fetch a row and return data in an array.
750
     *
751
     * @param resource $result result identifier
752
     * @param int $fetchmode ignored
753
     * @param int $rownum the row number to fetch
754
     * @return mixed data array or NULL on success, a MDB error on failure
755
     * @access public
756
     */
757
    function fetchInto(&$result, $fetchmode = MDB_FETCHMODE_DEFAULT, $rownum = null)
758
    {
759
        $result_value = $this->_querySimSignature($result);
760
        //if specific rownum request
761
        if ($rownum == null) {
762
            ++$this->highest_fetched_row[$result_value];
763
            $rownum = $this->highest_fetched_row[$result_value];
764
        } else {
765
            if (!isset($result[1][$rownum])) {
766
                return null;
767
            }
768
            $this->highest_fetched_row[$result_value] =
769
                max($this->highest_fetched_row[$result_value], $rownum);
770
        }
771
        if ($fetchmode == MDB_FETCHMODE_DEFAULT) {
772
            $fetchmode = $this->fetchmode;
773
        }
774
        // get row
775
        if(!$row = @$result[1][$rownum]) {
776
            return null;
777
        }
778
        // make row associative
779
        if (is_array($row) && $fetchmode & MDB_FETCHMODE_ASSOC) {
780
            foreach ($row as $key => $value) {
781
                $arraytemp[$result[0][$key]] = $value;
782
            }
783
            $row = $arraytemp;
784
            if ($this->options['optimize'] == 'portability') {
785
                $row = array_change_key_case($row, CASE_LOWER);
786
            }
787
        }
788
        return $row;
789
    }
790
    // }}}
791
 
792
    // {{{ nextResult()
793
 
794
    /**
795
     * Move the array result pointer to the next available row
796
     *
797
     * @param array a valid QuerySim result array
798
     * @return true if a result is available otherwise return false
799
     * @access public
800
     */
801
    function nextResult(&$result)
802
    {
803
        $result_value = $this->_querySimSignature($result);
804
        if (!isset($this->highest_fetched_row[$result_value])) {
805
            return $this->raiseError(MDB_ERROR_INVALID, null, null,
806
                'nextResult(): a non-existant result set was specified');
807
        }
808
        $result_value = $this->_querySimSignature($result);
809
        $setrow = ++$this->highest_fetched_row[$result_value];
810
        return isset($result[1][$setrow]) ? true : false;
811
    }
812
    // }}}
813
 
814
    // {{{ tableInfo()
815
 
816
    /**
817
    * returns meta data about the result set
818
    *
819
    * @param resource    $result    result identifier
820
    * @param mixed $mode depends on implementation
821
    * @return array an nested array, or a MDB error
822
    * @access public
823
    */
824
    //function tableInfo($result, $mode = null)
825
    //{
826
 
827
    //}
828
}
829
 
830
?>