thomascube
2005-11-08 583f1c8d80c42195d0ee41f30a885e13d777b79f
commit | author | age
c9462d 1 <?php
S 2 // +----------------------------------------------------------------------+
3 // | PHP versions 4 and 5                                                 |
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
6 // | Stig. S. Bakken, Lukas Smith                                         |
7 // | All rights reserved.                                                 |
8 // +----------------------------------------------------------------------+
9 // | MDB2 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 // | Author: Paul Cooper <pgc@ucecom.com>                                 |
43 // +----------------------------------------------------------------------+
44 //
45 // $Id$
46
47 require_once 'MDB2/Driver/Datatype/Common.php';
48
49 /**
50  * MDB2 PostGreSQL driver
51  *
52  * @package MDB2
53  * @category Database
54  * @author  Paul Cooper <pgc@ucecom.com>
55  */
56 class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common
57 {
58     // {{{ convertResult()
59
60     /**
61      * convert a value to a RDBMS independent MDB2 type
62      *
63      * @param mixed $value value to be converted
64      * @param int $type constant that specifies which type to convert to
65      * @return mixed converted value or a MDB2 error on failure
66      * @access public
67      */
68     function convertResult($value, $type)
69     {
70         if (is_null($value)) {
71             return null;
72         }
73         switch ($type) {
74         case 'boolean':
75             return $value == 't';
76         case 'float':
77             return doubleval($value);
78         case 'date':
79             return $value;
80         case 'time':
81             return $value;
82         case 'timestamp':
83             return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
84         default:
85             return $this->_baseConvertResult($value, $type);
86         }
87     }
88
89     // }}}
90     // {{{ getTypeDeclaration()
91
92     /**
93      * Obtain DBMS specific SQL code portion needed to declare an text type
94      * field to be used in statements like CREATE TABLE.
95      *
96      * @param array $field  associative array with the name of the properties
97      *      of the field being declared as array indexes. Currently, the types
98      *      of supported field properties are as follows:
99      *
100      *      length
101      *          Integer value that determines the maximum length of the text
102      *          field. If this argument is missing the field should be
103      *          declared to have the longest length allowed by the DBMS.
104      *
105      *      default
106      *          Text value to be used as default for this field.
107      *
108      *      notnull
109      *          Boolean flag that indicates whether this field is constrained
110      *          to not be set to null.
111      * @return string  DBMS specific SQL code portion that should be used to
112      *      declare the specified field.
113      * @access public
114      */
115     function getTypeDeclaration($field)
116     {
117         $db =& $this->getDBInstance();
118         if (PEAR::isError($db)) {
119             return $db;
120         }
121
122         switch ($field['type']) {
123         case 'text':
124             return array_key_exists('length', $field) ? 'VARCHAR ('.$field['length'].')' : 'TEXT';
125         case 'clob':
126             return 'OID';
127         case 'blob':
128             return 'OID';
129         case 'integer':
130             if (array_key_exists('autoincrement', $field) && $field['autoincrement']) {
131                 return 'SERIAL PRIMARY KEY';
132             }
133             return 'INT';
134         case 'boolean':
135             return 'BOOLEAN';
136         case 'date':
137             return 'DATE';
138         case 'time':
139             return 'TIME without time zone';
140         case 'timestamp':
141             return 'TIMESTAMP without time zone';
142         case 'float':
143             return 'FLOAT8';
144         case 'decimal':
145             return 'NUMERIC(18, '.$db->options['decimal_places'].')';
146         }
147     }
148
149     // }}}
150     // {{{ _getIntegerDeclaration()
151
152     /**
153      * Obtain DBMS specific SQL code portion needed to declare an integer type
154      * field to be used in statements like CREATE TABLE.
155      *
156      * @param string $name name the field to be declared.
157      * @param array $field associative array with the name of the properties
158      *       of the field being declared as array indexes. Currently, the types
159      *       of supported field properties are as follows:
160      *
161      *       unsigned
162      *           Boolean flag that indicates whether the field should be
163      *           declared as unsigned integer if possible.
164      *
165      *       default
166      *           Integer value to be used as default for this field.
167      *
168      *       notnull
169      *           Boolean flag that indicates whether this field is constrained
170      *           to not be set to null.
171      * @return string DBMS specific SQL code portion that should be used to
172      *       declare the specified field.
173      * @access protected
174      */
175     function _getIntegerDeclaration($name, $field)
176     {
177         if (array_key_exists('unsigned', $field) && $field['unsigned']) {
178             $db =& $this->getDBInstance();
179             if (PEAR::isError($db)) {
180                 return $db;
181             }
182
183             $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
184         }
185         if (array_key_exists('autoincrement', $field) && $field['autoincrement']) {
186             return $name.' '.$this->getTypeDeclaration($field);
187         }
188         $default = array_key_exists('default', $field) ? ' DEFAULT '.
189             $this->quote($field['default'], 'integer') : '';
190         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
191         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
192     }
193
194     // }}}
195     // {{{ _getTextDeclaration()
196
197     /**
198      * Obtain DBMS specific SQL code portion needed to declare a text type
199      * field to be used in statements like CREATE TABLE.
200      *
201      * @param string $name   name the field to be declared.
202      * @param array $field  associative array with the name of the properties
203      *      of the field being declared as array indexes. Currently, the types
204      *      of supported field properties are as follows:
205      *
206      *      length
207      *          Integer value that determines the maximum length of the text
208      *          field. If this argument is missing the field should be
209      *          declared to have the longest length allowed by the DBMS.
210      *
211      *      default
212      *          Text value to be used as default for this field.
213      *
214      *      notnull
215      *          Boolean flag that indicates whether this field is constrained
216      *          to not be set to null.
217      * @return string  DBMS specific SQL code portion that should be used to
218      *      declare the specified field.
219      * @access protected
220      */
221     function _getTextDeclaration($name, $field)
222     {
223         $default = array_key_exists('default', $field) ? ' DEFAULT '.
224             $this->quote($field['default'], 'text') : '';
225         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
226         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
227     }
228
229     // }}}
230     // {{{ _getCLOBDeclaration()
231
232     /**
233      * Obtain DBMS specific SQL code portion needed to declare a character
234      * large object type field to be used in statements like CREATE TABLE.
235      *
236      * @param string $name   name the field to be declared.
237      * @param array $field  associative array with the name of the properties
238      *      of the field being declared as array indexes. Currently, the types
239      *      of supported field properties are as follows:
240      *
241      *      length
242      *          Integer value that determines the maximum length of the large
243      *          object field. If this argument is missing the field should be
244      *          declared to have the longest length allowed by the DBMS.
245      *
246      *      notnull
247      *          Boolean flag that indicates whether this field is constrained
248      *          to not be set to null.
249      * @return string  DBMS specific SQL code portion that should be used to
250      *      declare the specified field.
251      * @access protected
252      */
253     function _getCLOBDeclaration($name, $field)
254     {
255         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
256         return $name.' '.$this->getTypeDeclaration($field).$notnull;
257     }
258
259     // }}}
260     // {{{ _getBLOBDeclaration()
261
262     /**
263      * Obtain DBMS specific SQL code portion needed to declare a binary large
264      * object type field to be used in statements like CREATE TABLE.
265      *
266      * @param string $name   name the field to be declared.
267      * @param array $field  associative array with the name of the properties
268      *      of the field being declared as array indexes. Currently, the types
269      *      of supported field properties are as follows:
270      *
271      *      length
272      *          Integer value that determines the maximum length of the large
273      *          object field. If this argument is missing the field should be
274      *          declared to have the longest length allowed by the DBMS.
275      *
276      *      notnull
277      *          Boolean flag that indicates whether this field is constrained
278      *          to not be set to null.
279      * @return string  DBMS specific SQL code portion that should be used to
280      *      declare the specified field.
281      * @access protected
282      */
283     function _getBLOBDeclaration($name, $field)
284     {
285         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
286         return $name.' '.$this->getTypeDeclaration($field).$notnull;
287     }
288
289     // }}}
290     // {{{ _getBooleanDeclaration()
291
292     /**
293      * Obtain DBMS specific SQL code portion needed to declare a boolean type
294      * field to be used in statements like CREATE TABLE.
295      *
296      * @param string $name name the field to be declared.
297      * @param array $field associative array with the name of the properties
298      *       of the field being declared as array indexes. Currently, the types
299      *       of supported field properties are as follows:
300      *
301      *       default
302      *           Boolean value to be used as default for this field.
303      *
304      *       notnullL
305      *           Boolean flag that indicates whether this field is constrained
306      *           to not be set to null.
307      * @return string DBMS specific SQL code portion that should be used to
308      *       declare the specified field.
309      * @access protected
310      */
311     function _getBooleanDeclaration($name, $field)
312     {
313         $default = array_key_exists('default', $field) ? ' DEFAULT '.
314             $this->quote($field['default'], 'boolean') : '';
315         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
316         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
317     }
318
319     // }}}
320     // {{{ _getDateDeclaration()
321
322     /**
323      * Obtain DBMS specific SQL code portion needed to declare a date type
324      * field to be used in statements like CREATE TABLE.
325      *
326      * @param string $name   name the field to be declared.
327      * @param array $field  associative array with the name of the properties
328      *      of the field being declared as array indexes. Currently, the types
329      *      of supported field properties are as follows:
330      *
331      *      default
332      *          Date value to be used as default for this field.
333      *
334      *      notnull
335      *          Boolean flag that indicates whether this field is constrained
336      *          to not be set to null.
337      * @return string  DBMS specific SQL code portion that should be used to
338      *      declare the specified field.
339      * @access protected
340      */
341     function _getDateDeclaration($name, $field)
342     {
343         $default = array_key_exists('default', $field) ? ' DEFAULT '.
344             $this->quote($field['default'], 'date') : '';
345         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
346         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
347     }
348
349     // }}}
350     // {{{ _getTimeDeclaration()
351
352     /**
353      * Obtain DBMS specific SQL code portion needed to declare a time
354      * field to be used in statements like CREATE TABLE.
355      *
356      * @param string $name   name the field to be declared.
357      * @param array $field  associative array with the name of the properties
358      *      of the field being declared as array indexes. Currently, the types
359      *      of supported field properties are as follows:
360      *
361      *      default
362      *          Time value to be used as default for this field.
363      *
364      *      notnull
365      *          Boolean flag that indicates whether this field is constrained
366      *          to not be set to null.
367      * @return string  DBMS specific SQL code portion that should be used to
368      *      declare the specified field.
369      * @access protected
370      */
371     function _getTimeDeclaration($name, $field)
372     {
373         $default = array_key_exists('default', $field) ? ' DEFAULT '.
374             $this->quote($field['default'], 'time') : '';
375         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
376         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
377     }
378
379     // }}}
380     // {{{ _getTimestampDeclaration()
381
382     /**
383      * Obtain DBMS specific SQL code portion needed to declare a timestamp
384      * field to be used in statements like CREATE TABLE.
385      *
386      * @param string $name name the field to be declared.
387      * @param array $field associative array with the name of the properties
388      *       of the field being declared as array indexes. Currently, the types
389      *       of supported field properties are as follows:
390      *
391      *       default
392      *           Timestamp value to be used as default for this field.
393      *
394      *       notnull
395      *           Boolean flag that indicates whether this field is constrained
396      *           to not be set to null.
397      * @return string DBMS specific SQL code portion that should be used to
398      *       declare the specified field.
399      * @access protected
400      */
401     function _getTimestampDeclaration($name, $field)
402     {
403         $default = array_key_exists('default', $field) ? ' DEFAULT '.
404             $this->quote($field['default'], 'timestamp') : '';
405         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
406         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
407     }
408
409     // }}}
410     // {{{ _getFloatDeclaration()
411
412     /**
413      * Obtain DBMS specific SQL code portion needed to declare a float type
414      * field to be used in statements like CREATE TABLE.
415      *
416      * @param string $name   name the field to be declared.
417      * @param array $field  associative array with the name of the properties
418      *      of the field being declared as array indexes. Currently, the types
419      *      of supported field properties are as follows:
420      *
421      *      default
422      *          Float value to be used as default for this field.
423      *
424      *      notnull
425      *          Boolean flag that indicates whether this field is constrained
426      *          to not be set to null.
427      * @return string  DBMS specific SQL code portion that should be used to
428      *      declare the specified field.
429      * @access protected
430      */
431     function _getFloatDeclaration($name, $field)
432     {
433         $default = array_key_exists('default', $field) ? ' DEFAULT '.
434             $this->quote($field['default'], 'float') : '';
435         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
436         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
437     }
438
439     // }}}
440     // {{{ _getDecimalDeclaration()
441
442     /**
443      * Obtain DBMS specific SQL code portion needed to declare a decimal type
444      * field to be used in statements like CREATE TABLE.
445      *
446      * @param string $name   name the field to be declared.
447      * @param array $field  associative array with the name of the properties
448      *      of the field being declared as array indexes. Currently, the types
449      *      of supported field properties are as follows:
450      *
451      *      default
452      *          Decimal value to be used as default for this field.
453      *
454      *      notnull
455      *          Boolean flag that indicates whether this field is constrained
456      *          to not be set to null.
457      * @return string  DBMS specific SQL code portion that should be used to
458      *      declare the specified field.
459      * @access protected
460      */
461     function _getDecimalDeclaration($name, $field)
462     {
463         $db =& $this->getDBInstance();
464         if (PEAR::isError($db)) {
465             return $db;
466         }
467
468         $default = array_key_exists('default', $field) ? ' DEFAULT '.
469             $this->quote($field['default'], 'float') : '';
470         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
471         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
472     }
473
474     // }}}
475     // {{{ _quoteLOB()
476
477     /**
478      * Convert a text value into a DBMS specific format that is suitable to
479      * compose query statements.
480      *
481      * @param           $value
482      * @return string text string that represents the given argument value in
483      *      a DBMS specific format.
484      * @access protected
485      */
486     function _quoteLOB($value)
487     {
488         $db =& $this->getDBInstance();
489         if (PEAR::isError($db)) {
490             return $db;
491         }
492
493         $connect = $db->connect();
494         if (PEAR::isError($connect)) {
495             return $connect;
496         }
497         if (!$db->in_transaction && !@pg_query($db->connection, 'BEGIN')) {
498             return $db->raiseError(MDB2_ERROR, null, null,
499                 'error starting transaction');
500         }
501         if (is_resource($value)) {
502             $close = false;
503         } elseif (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
504             $close = true;
505             if ($match[1] == 'file://') {
506                 $value = $match[2];
507             }
508             // disabled use of pg_lo_import() for now with the following line
509             $value = @fopen($value, 'r');
510         } else {
511             $close = true;
512             $fp = @tmpfile();
513             @fwrite($fp, $value);
514             @rewind($fp);
515             $value = $fp;
516         }
517         $result = false;
518         if (is_resource($value)) {
519             if (($lo = @pg_lo_create($db->connection))) {
520                 if (($handle = @pg_lo_open($db->connection, $lo, 'w'))) {
521                     while (!@feof($value)) {
522                         $data = @fread($value, $db->options['lob_buffer_length']);
523                         if ($data === '') {
524                             break;
525                         }
526                         if (!@pg_lo_write($handle, $data)) {
527                             $result = $db->raiseError();
528                             break;
529                         }
530                     }
531                     if (!PEAR::isError($result)) {
532                         $result = strval($lo);
533                     }
534                     @pg_lo_close($handle);
535                 } else {
536                     $result = $db->raiseError();
537                     @pg_lo_unlink($db->connection, $lo);
538                 }
539             }
540             if ($close) {
541                 @fclose($value);
542             }
543         } else {
544             if (!@pg_lo_import($db->connection, $value)) {
545                 $result = $db->raiseError();
546             }
547         }
548         if (!$db->in_transaction) {
549             if (PEAR::isError($result)) {
550                 @pg_query($db->connection, 'ROLLBACK');
551             } else {
552                 @pg_query($db->connection, 'COMMIT');
553             }
554         }
555         return $result;
556     }
557
558     // }}}
559     // {{{ _quoteCLOB()
560
561     /**
562      * Convert a text value into a DBMS specific format that is suitable to
563      * compose query statements.
564      *
565      * @param           $value
566      * @return string text string that represents the given argument value in
567      *      a DBMS specific format.
568      * @access protected
569      */
570     function _quoteCLOB($value)
571     {
572         return $this->_quoteLOB($value);
573     }
574
575     // }}}
576     // {{{ _quoteBLOB()
577
578     /**
579      * Convert a text value into a DBMS specific format that is suitable to
580      * compose query statements.
581      *
582      * @param           $value
583      * @return string text string that represents the given argument value in
584      *      a DBMS specific format.
585      * @access protected
586      */
587     function _quoteBLOB($value)
588     {
589         return $this->_quoteLOB($value);
590     }
591
592     // }}}
593     // {{{ _quoteBoolean()
594
595     /**
596      * Convert a text value into a DBMS specific format that is suitable to
597      * compose query statements.
598      *
599      * @param string $value text string value that is intended to be converted.
600      * @return string text string that represents the given argument value in
601      *       a DBMS specific format.
602      * @access protected
603      */
604     function _quoteBoolean($value)
605     {
606         return ($value ? "'t'" : "'f'");
607     }
608
609     // }}}
610     // {{{ _quoteFloat()
611
612     /**
613      * Convert a text value into a DBMS specific format that is suitable to
614      * compose query statements.
615      *
616      * @param string $value text string value that is intended to be converted.
617      * @return string text string that represents the given argument value in
618      *      a DBMS specific format.
619      * @access protected
620      */
621     function _quoteFloat($value)
622     {
623         return (float)$value;
624     }
625
626     // }}}
627     // {{{ _quoteDecimal()
628
629     /**
630      * Convert a text value into a DBMS specific format that is suitable to
631      * compose query statements.
632      *
633      * @param string $value text string value that is intended to be converted.
634      * @return string text string that represents the given argument value in
635      *      a DBMS specific format.
636      * @access protected
637      */
638     function _quoteDecimal($value)
639     {
640         $db =& $this->getDBInstance();
641         if (PEAR::isError($db)) {
642             return $db;
643         }
644
645         return $db->escape($value);
646     }
647
648     // }}}
649     // {{{ writeLOBToFile()
650
651     /**
652      * retrieve LOB from the database
653      *
654      * @param resource $lob stream handle
655      * @param string $file name of the file into which the LOb should be fetched
656      * @return mixed MDB2_OK on success, a MDB2 error on failure
657      * @access protected
658      */
659     function writeLOBToFile($lob, $file)
660     {
661         $db =& $this->getDBInstance();
662         if (PEAR::isError($db)) {
663             return $db;
664         }
665
666         $lob_data = stream_get_meta_data($lob);
667         $lob_index = $lob_data['wrapper_data']->lob_index;
668         if (!pg_lo_export($db->connection, $this->lobs[$lob_index]['ressource'], $file)) {
669             return $db->raiseError();
670         }
671         return MDB2_OK;
672     }
673
674     // }}}
675     // {{{ _retrieveLOB()
676
677     /**
678      * retrieve LOB from the database
679      *
680      * @param resource $lob stream handle
681      * @return mixed MDB2_OK on success, a MDB2 error on failure
682      * @access protected
683      */
684     function _retrieveLOB(&$lob)
685     {
686         if (!array_key_exists('handle', $lob)) {
687             $db =& $this->getDBInstance();
688             if (PEAR::isError($db)) {
689                 return $db;
690             }
691             if (!$db->in_transaction) {
692                 if (!@pg_query($db->connection, 'BEGIN')) {
693                     return $db->raiseError();
694                 }
695                 $lob['in_transaction'] = true;
696             }
697             $lob['handle'] = @pg_lo_open($db->connection, $lob['ressource'], 'r');
698             if (!$lob['handle']) {
699                 if (array_key_exists('in_transaction', $lob)) {
700                     @pg_query($db->connection, 'END');
701                     unset($lob['in_transaction']);
702                 }
703                 return $db->raiseError();
704             }
705         }
706         return MDB2_OK;
707     }
708
709     // }}}
710     // {{{ _readLOB()
711
712     /**
713      * Read data from large object input stream.
714      *
715      * @param resource $lob stream handle
716      * @param blob $data reference to a variable that will hold data to be
717      *      read from the large object input stream
718      * @param int $length integer value that indicates the largest ammount of
719      *      data to be read from the large object input stream.
720      * @return mixed length on success, a MDB2 error on failure
721      * @access protected
722      */
723     function _readLOB($lob, $length)
724     {
725         $data = @pg_lo_read($lob['handle'], $length);
726         if (!is_string($data)) {
727             $db =& $this->getDBInstance();
728             if (PEAR::isError($db)) {
729                 return $db;
730             }
731
732             return $db->raiseError();
733         }
734         return $data;
735     }
736
737     // }}}
738     // {{{ _destroyLOB()
739
740     /**
741      * Free any resources allocated during the lifetime of the large object
742      * handler object.
743      *
744      * @param int $lob_index from the lob array
745      * @access protected
746      */
747     function _destroyLOB($lob_index)
748     {
749         if (isset($this->lobs[$lob_index]['handle'])) {
750             @pg_lo_close($this->lobs[$lob_index]['handle']);
751             unset($this->lobs[$lob_index]['handle']);
752             if (isset($this->lobs[$lob_index]['in_transaction'])) {
753 /*
754 for some reason this piece of code causes an apache crash
755                 $db =& $this->getDBInstance();
756                 if (PEAR::isError($db)) {
757                     return $db;
758                 }
759
760                 @pg_query($db->connection, 'END');
761 */
762             }
763         }
764     }
765
766     // }}}
767     // {{{ mapNativeDatatype()
768
769     /**
770      * Maps a native array description of a field to a MDB2 datatype and length
771      *
772      * @param array  $field native field description
773      * @return array containing the various possible types and the length
774      * @access public
775      */
776     function mapNativeDatatype($field)
777     {
778         $db_type = preg_replace('/\d/','', strtolower($field['typname']) );
779         $length = $field['attlen'];
780         if ($length == '-1') {
781             $length = $field['atttypmod']-4;
782         }
783         if ((int)$length <= 0) {
784             $length = null;
785         }
786         $type = array();
787         switch ($db_type) {
788         case 'int':
789             $type[] = 'integer';
790             if ($length == '1') {
791                 $type[] = 'boolean';
792             }
793             break;
794         case 'bool':
795             $type[] = 'boolean';
796             $length = null;
797             break;
798         case 'text':
799         case 'char':
800         case 'varchar':
801         case 'bpchar':
802             $type[] = 'text';
803             if ($length == '1') {
804                 $type[] = 'boolean';
805             } elseif (strstr($db_type, 'text'))
806                 $type[] = 'clob';
807             break;
808         case 'date':
809             $type[] = 'date';
810             $length = null;
811             break;
812         case 'datetime':
813         case 'timestamp':
814             $type[] = 'timestamp';
815             $length = null;
816             break;
817         case 'time':
818             $type[] = 'time';
819             $length = null;
820             break;
821         case 'float':
822         case 'double':
823         case 'real':
824             $type[] = 'float';
825             break;
826         case 'decimal':
827         case 'money':
828         case 'numeric':
829             $type[] = 'decimal';
830             break;
831         case 'tinyblob':
832         case 'mediumblob':
833         case 'longblob':
834         case 'blob':
835             $type[] = 'blob';
836             $length = null;
837             break;
838         case 'oid':
839             $type[] = 'blob';
840             $type[] = 'clob';
841             $length = null;
842             break;
843         case 'year':
844             $type[] = 'integer';
845             $type[] = 'date';
846             $length = null;
847             break;
848         default:
849             $db =& $this->getDBInstance();
850             if (PEAR::isError($db)) {
851                 return $db;
852             }
853
854             return $db->raiseError(MDB2_ERROR, null, null,
855                 'getTableFieldDefinition: unknown database attribute type');
856         }
857
858         return array($type, $length);
859     }
860
861     // }}}
862 }
863 ?>