thomascube
2006-03-04 f5121b5639992fc9e51fd551bac2254429b638fa
commit | author | age
d13c36 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: Lukas Smith <smith@pooteeweet.org>                           |
43 // +----------------------------------------------------------------------+
44 //
45 // $Id$
46
47 require_once 'MDB2/LOB.php';
48
49 /**
50  * @package  MDB2
51  * @category Database
52  * @author   Lukas Smith <smith@pooteeweet.org>
53  */
54
55 /**
56  * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
57  *
58  * @package MDB2
59  * @category Database
60  * @author Lukas Smith <smith@pooteeweet.org>
61  */
62 class MDB2_Driver_Datatype_Common extends MDB2_Module_Common
63 {
64     var $valid_types = array(
65         'text'      => true,
66         'boolean'   => true,
67         'integer'   => true,
68         'decimal'   => true,
69         'float'     => true,
70         'date'      => true,
71         'time'      => true,
72         'timestamp' => true,
73         'clob'      => true,
74         'blob'      => true,
75     );
76
77     /**
78      * contains all LOB objects created with this MDB2 instance
79     * @var array
80     * @access protected
81     */
82     var $lobs = array();
83
84     // }}}
85     // {{{ setResultTypes()
86
87     /**
88      * Define the list of types to be associated with the columns of a given
89      * result set.
90      *
91      * This function may be called before invoking fetchRow(), fetchOne()
92      * fetchCole() and fetchAll() so that the necessary data type
93      * conversions are performed on the data to be retrieved by them. If this
94      * function is not called, the type of all result set columns is assumed
95      * to be text, thus leading to not perform any conversions.
96      *
97      * @param resource $result result identifier
98      * @param string $types array variable that lists the
99      *       data types to be expected in the result set columns. If this array
100      *       contains less types than the number of columns that are returned
101      *       in the result set, the remaining columns are assumed to be of the
102      *       type text. Currently, the types clob and blob are not fully
103      *       supported.
104      * @return mixed MDB2_OK on success, a MDB2 error on failure
105      * @access public
106      */
107     function setResultTypes(&$result, $types)
108     {
109         $types = is_array($types) ? array_values($types) : array($types);
110         foreach ($types as $key => $type) {
111             if (!isset($this->valid_types[$type])) {
112                 $db =& $this->getDBInstance();
113                 if (PEAR::isError($db)) {
114                     return $db;
115                 }
116
117                 return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
118                     'setResultTypes: ' . $type . ' for '. $key .' is not a supported column type');
119             }
120         }
121         $result->types = $types;
122         return MDB2_OK;
123     }
124
125     // }}}
126     // {{{ _baseConvertResult()
127
128     /**
129      * general type conversion method
130      *
131      * @param mixed $value refernce to a value to be converted
132      * @param int $type constant that specifies which type to convert to
133      * @return object a MDB2 error on failure
134      * @access protected
135      */
136     function _baseConvertResult($value, $type)
137     {
138         switch ($type) {
139         case 'text':
140             return $value;
141         case 'integer':
142             return intval($value);
143         case 'boolean':
144             return $value == 'Y';
145         case 'decimal':
146             return $value;
147         case 'float':
148             return doubleval($value);
149         case 'date':
150             return $value;
151         case 'time':
152             return $value;
153         case 'timestamp':
154             return $value;
155         case 'clob':
156         case 'blob':
157             $this->lobs[] = array(
158                 'buffer' => null,
159                 'position' => 0,
160                 'lob_index' => null,
161                 'endOfLOB' => false,
162                 'ressource' => $value,
163                 'value' => null,
164             );
165             end($this->lobs);
166             $lob_index = key($this->lobs);
167             $this->lobs[$lob_index]['lob_index'] = $lob_index;
168             return fopen('MDB2LOB://'.$lob_index.'@'.$this->db_index, 'r+');
169         }
170
171         $db =& $this->getDBInstance();
172         if (PEAR::isError($db)) {
173             return $db;
174         }
175
176         return $db->raiseError(MDB2_ERROR_INVALID, null, null,
177             'attempt to convert result value to an unknown type ' . $type);
178     }
179
180     // }}}
181     // {{{ convertResult()
182
183     /**
184      * convert a value to a RDBMS indepdenant MDB2 type
185      *
186      * @param mixed $value value to be converted
187      * @param int $type constant that specifies which type to convert to
188      * @return mixed converted value or a MDB2 error on failure
189      * @access public
190      */
191     function convertResult($value, $type)
192     {
193         if (is_null($value)) {
194             return null;
195         }
196         return $this->_baseConvertResult($value, $type);
197     }
198
199     // }}}
200     // {{{ convertResultRow()
201
202     /**
203      * convert a result row
204      *
205      * @param resource $result result identifier
206      * @param array $row array with data
207      * @return mixed MDB2_OK on success,  a MDB2 error on failure
208      * @access public
209      */
210     function convertResultRow($types, $row)
211     {
212         if (is_array($types)) {
213             $current_column = -1;
214             foreach ($row as $key => $column) {
215                 ++$current_column;
216                 if (!isset($column) || !isset($types[$current_column])) {
217                     continue;
218                 }
219                 $value = $this->convertResult($row[$key], $types[$current_column]);
220                 if (PEAR::isError($value)) {
221                     return $value;
222                 }
223                 $row[$key] = $value;
224             }
225         }
226         return $row;
227     }
228
229     // }}}
230     // {{{ getDeclaration()
231
232     /**
233      * Obtain DBMS specific SQL code portion needed to declare
234      * of the given type
235      *
236      * @param string $type type to which the value should be converted to
237      * @param string  $name   name the field to be declared.
238      * @param string  $field  definition of the field
239      * @return string  DBMS specific SQL code portion that should be used to
240      *                 declare the specified field.
241      * @access public
242      */
243     function getDeclaration($type, $name, $field)
244     {
245         if (!method_exists($this, "_get{$type}Declaration")) {
246             $db =& $this->getDBInstance();
247             if (PEAR::isError($db)) {
248                 return $db;
249             }
250
251             return $db->raiseError('type not defined: '.$type);
252         }
253         return $this->{"_get{$type}Declaration"}($name, $field);
254     }
255
256     // }}}
257     // {{{ _getIntegerDeclaration()
258
259     /**
260      * Obtain DBMS specific SQL code portion needed to declare an integer type
261      * field to be used in statements like CREATE TABLE.
262      *
263      * @param string $name name the field to be declared.
264      * @param array $field associative array with the name of the properties
265      *       of the field being declared as array indexes. Currently, the types
266      *       of supported field properties are as follows:
267      *
268      *       unsigned
269      *           Boolean flag that indicates whether the field should be
270      *           declared as unsigned integer if possible.
271      *
272      *       default
273      *           Integer value to be used as default for this field.
274      *
275      *       notnull
276      *           Boolean flag that indicates whether this field is constrained
277      *           to not be set to null.
278      * @return string DBMS specific SQL code portion that should be used to
279      *       declare the specified field.
280      * @access protected
281      */
282     function _getIntegerDeclaration($name, $field)
283     {
284         if (array_key_exists('unsigned', $field) && $field['unsigned']) {
285             $db =& $this->getDBInstance();
286             if (PEAR::isError($db)) {
287                 return $db;
288             }
289
290             $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
291         }
292         $default = array_key_exists('default', $field) ? ' DEFAULT '.
293             $this->quote($field['default'], 'integer') : '';
294         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
295         return $name.' INT'.$default.$notnull;
296     }
297
298     // }}}
299     // {{{ _getTextDeclaration()
300
301     /**
302      * Obtain DBMS specific SQL code portion needed to declare an text type
303      * field to be used in statements like CREATE TABLE.
304      *
305      * @param string $name name the field to be declared.
306      * @param array $field associative array with the name of the properties
307      *       of the field being declared as array indexes. Currently, the types
308      *       of supported field properties are as follows:
309      *
310      *       length
311      *           Integer value that determines the maximum length of the text
312      *           field. If this argument is missing the field should be
313      *           declared to have the longest length allowed by the DBMS.
314      *
315      *       default
316      *           Text value to be used as default for this field.
317      *
318      *       notnull
319      *           Boolean flag that indicates whether this field is constrained
320      *           to not be set to null.
321      * @return string DBMS specific SQL code portion that should be used to
322      *       declare the specified field.
323      * @access protected
324      */
325     function _getTextDeclaration($name, $field)
326     {
327         $default = array_key_exists('default', $field) ? ' DEFAULT '.
328             $this->quote($field['default'], 'text') : '';
329         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
330         $type = array_key_exists('length', $field) ? 'CHAR ('.$field['length'].')' : 'TEXT';
331         return $name.' '.$type.$default.$notnull;
332     }
333
334     // }}}
335     // {{{ _getCLOBDeclaration()
336
337     /**
338      * Obtain DBMS specific SQL code portion needed to declare an character
339      * large object type field to be used in statements like CREATE TABLE.
340      *
341      * @param string $name name the field to be declared.
342      * @param array $field associative array with the name of the properties
343      *       of the field being declared as array indexes. Currently, the types
344      *       of supported field properties are as follows:
345      *
346      *       length
347      *           Integer value that determines the maximum length of the large
348      *           object field. If this argument is missing the field should be
349      *           declared to have the longest length allowed by the DBMS.
350      *
351      *       notnull
352      *           Boolean flag that indicates whether this field is constrained
353      *           to not be set to null.
354      * @return string DBMS specific SQL code portion that should be used to
355      *       declare the specified field.
356      * @access protected
357      */
358     function _getCLOBDeclaration($name, $field)
359     {
360         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
361         $type = array_key_exists('length', $field) ? 'CHAR ('.$field['length'].')' : 'TEXT';
362         return $name.' '.$type.$notnull;
363     }
364
365     // }}}
366     // {{{ _getBLOBDeclaration()
367
368     /**
369      * Obtain DBMS specific SQL code portion needed to declare an binary large
370      * object type field to be used in statements like CREATE TABLE.
371      *
372      * @param string $name name the field to be declared.
373      * @param array $field associative array with the name of the properties
374      *       of the field being declared as array indexes. Currently, the types
375      *       of supported field properties are as follows:
376      *
377      *       length
378      *           Integer value that determines the maximum length of the large
379      *           object field. If this argument is missing the field should be
380      *           declared to have the longest length allowed by the DBMS.
381      *
382      *       notnull
383      *           Boolean flag that indicates whether this field is constrained
384      *           to not be set to null.
385      * @return string DBMS specific SQL code portion that should be used to
386      *       declare the specified field.
387      * @access protected
388      */
389     function _getBLOBDeclaration($name, $field)
390     {
391         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
392         $type = array_key_exists('length', $field) ? 'CHAR ('.$field['length'].')' : 'TEXT';
393         return $name.' '.$type.$notnull;
394     }
395
396     // }}}
397     // {{{ _getBooleanDeclaration()
398
399     /**
400      * Obtain DBMS specific SQL code portion needed to declare a boolean type
401      * field to be used in statements like CREATE TABLE.
402      *
403      * @param string $name name the field to be declared.
404      * @param array $field associative array with the name of the properties
405      *       of the field being declared as array indexes. Currently, the types
406      *       of supported field properties are as follows:
407      *
408      *       default
409      *           Boolean value to be used as default for this field.
410      *
411      *       notnullL
412      *           Boolean flag that indicates whether this field is constrained
413      *           to not be set to null.
414      * @return string DBMS specific SQL code portion that should be used to
415      *       declare the specified field.
416      * @access protected
417      */
418     function _getBooleanDeclaration($name, $field)
419     {
420         $default = array_key_exists('default', $field) ? ' DEFAULT '.
421             $this->quote($field['default'], 'boolean') : '';
422         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
423         return $name.' CHAR (1)'.$default.$notnull;
424     }
425
426     // }}}
427     // {{{ _getDateDeclaration()
428
429     /**
430      * Obtain DBMS specific SQL code portion needed to declare a date type
431      * field to be used in statements like CREATE TABLE.
432      *
433      * @param string $name name the field to be declared.
434      * @param array $field associative array with the name of the properties
435      *       of the field being declared as array indexes. Currently, the types
436      *       of supported field properties are as follows:
437      *
438      *       default
439      *           Date value to be used as default for this field.
440      *
441      *       notnull
442      *           Boolean flag that indicates whether this field is constrained
443      *           to not be set to null.
444      * @return string DBMS specific SQL code portion that should be used to
445      *       declare the specified field.
446      * @access protected
447      */
448     function _getDateDeclaration($name, $field)
449     {
450         $default = array_key_exists('default', $field) ? ' DEFAULT '.
451             $this->quote($field['default'], 'date') : '';
452         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
453         return $name.' CHAR ('.strlen('YYYY-MM-DD').')'.$default.$notnull;
454     }
455
456     // }}}
457     // {{{ _getTimestampDeclaration()
458
459     /**
460      * Obtain DBMS specific SQL code portion needed to declare a timestamp
461      * field to be used in statements like CREATE TABLE.
462      *
463      * @param string $name name the field to be declared.
464      * @param array $field associative array with the name of the properties
465      *       of the field being declared as array indexes. Currently, the types
466      *       of supported field properties are as follows:
467      *
468      *       default
469      *           Timestamp value to be used as default for this field.
470      *
471      *       notnull
472      *           Boolean flag that indicates whether this field is constrained
473      *           to not be set to null.
474      * @return string DBMS specific SQL code portion that should be used to
475      *       declare the specified field.
476      * @access protected
477      */
478     function _getTimestampDeclaration($name, $field)
479     {
480         $default = array_key_exists('default', $field) ? ' DEFAULT '.
481             $this->quote($field['default'], 'timestamp') : '';
482         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
483         return $name.' CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')'.$default.$notnull;
484     }
485
486     // }}}
487     // {{{ _getTimeDeclaration()
488
489     /**
490      * Obtain DBMS specific SQL code portion needed to declare a time
491      * field to be used in statements like CREATE TABLE.
492      *
493      * @param string $name name the field to be declared.
494      * @param array $field associative array with the name of the properties
495      *       of the field being declared as array indexes. Currently, the types
496      *       of supported field properties are as follows:
497      *
498      *       default
499      *           Time value to be used as default for this field.
500      *
501      *       notnull
502      *           Boolean flag that indicates whether this field is constrained
503      *           to not be set to null.
504      * @return string DBMS specific SQL code portion that should be used to
505      *       declare the specified field.
506      * @access protected
507      */
508     function _getTimeDeclaration($name, $field)
509     {
510         $default = array_key_exists('default', $field) ? ' DEFAULT '.
511             $this->quote($field['default'], 'time') : '';
512         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
513         return $name.' CHAR ('.strlen('HH:MM:SS').')'.$default.$notnull;
514     }
515
516     // }}}
517     // {{{ _getFloatDeclaration()
518
519     /**
520      * Obtain DBMS specific SQL code portion needed to declare a float type
521      * field to be used in statements like CREATE TABLE.
522      *
523      * @param string $name name the field to be declared.
524      * @param array $field associative array with the name of the properties
525      *       of the field being declared as array indexes. Currently, the types
526      *       of supported field properties are as follows:
527      *
528      *       default
529      *           Float value to be used as default for this field.
530      *
531      *       notnull
532      *           Boolean flag that indicates whether this field is constrained
533      *           to not be set to null.
534      * @return string DBMS specific SQL code portion that should be used to
535      *       declare the specified field.
536      * @access protected
537      */
538     function _getFloatDeclaration($name, $field)
539     {
540         $default = array_key_exists('default', $field) ? ' DEFAULT '.
541             $this->quote($field['default'], 'float') : '';
542         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
543         return $name.' TEXT'.$default.$notnull;
544     }
545
546     // }}}
547     // {{{ _getDecimalDeclaration()
548
549     /**
550      * Obtain DBMS specific SQL code portion needed to declare a decimal type
551      * field to be used in statements like CREATE TABLE.
552      *
553      * @param string $name name the field to be declared.
554      * @param array $field associative array with the name of the properties
555      *       of the field being declared as array indexes. Currently, the types
556      *       of supported field properties are as follows:
557      *
558      *       default
559      *           Decimal value to be used as default for this field.
560      *
561      *       notnull
562      *           Boolean flag that indicates whether this field is constrained
563      *           to not be set to null.
564      * @return string DBMS specific SQL code portion that should be used to
565      *       declare the specified field.
566      * @access protected
567      */
568     function _getDecimalDeclaration($name, $field)
569     {
570         $default = array_key_exists('default', $field) ? ' DEFAULT '.
571             $this->quote($field['default'], 'decimal') : '';
572         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
573         return $name.' TEXT'.$default.$notnull;
574     }
575
576     // }}}
577     // {{{ compareDefinition()
578
579     /**
580      * Obtain an array of changes that may need to applied
581      *
582      * @param array $current new definition
583      * @param array  $previous old definition
584      * @return array  containg all changes that will need to be applied
585      * @access public
586      */
587     function compareDefinition($current, $previous)
588     {
589         $type = array_key_exists('type', $current) ? $current['type'] : null;
590
591         if (!method_exists($this, "_compare{$type}Definition")) {
592             $db =& $this->getDBInstance();
593             if (PEAR::isError($db)) {
594                 return $db;
595             }
596
597             return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
598                 'type "'.$current['type'].'" is not yet supported');
599         }
600
601         if (!array_key_exists('type', $previous) || $previous['type'] != $type) {
602             return $current;
603         }
604
605         $change = $this->{"_compare{$type}Definition"}($current, $previous);
606
607         $previous_notnull = array_key_exists('notnull', $previous) ? $previous['notnull'] : false;
608         $notnull = array_key_exists('notnull', $current) ? $current['notnull'] : false;
609         if ($previous_notnull != $notnull) {
610             $change['notnull'] = true;
611         }
612
613         $previous_default = array_key_exists('default', $previous) ? $previous['default'] :
614             ($previous_notnull ? '' : null);
615         $default = array_key_exists('default', $current) ? $current['default'] :
616             ($notnull ? '' : null);
617         if ($previous_default !== $default) {
618             $change['default'] = true;
619         }
620
621         return $change;
622     }
623
624     // }}}
625     // {{{ _compareIntegerDefinition()
626
627     /**
628      * Obtain an array of changes that may need to applied to an integer field
629      *
630      * @param array $current new definition
631      * @param array  $previous old definition
632      * @return array  containg all changes that will need to be applied
633      * @access protected
634      */
635     function _compareIntegerDefinition($current, $previous)
636     {
637         $change = array();
638         $previous_unsigned = array_key_exists('unsigned', $previous) ? $previous['unsigned'] : false;
639         $unsigned = array_key_exists('unsigned', $current) ? $current['unsigned'] : false;
640         if ($previous_unsigned != $unsigned) {
641             $change['unsigned'] = true;
642         }
643         $previous_autoincrement = array_key_exists('autoincrement', $previous) ? $previous['autoincrement'] : false;
644         $autoincrement = array_key_exists('autoincrement', $current) ? $current['autoincrement'] : false;
645         if ($previous_autoincrement != $autoincrement) {
646             $change['autoincrement'] = true;
647         }
648         return $change;
649     }
650
651     // }}}
652     // {{{ _compareTextDefinition()
653
654     /**
655      * Obtain an array of changes that may need to applied to an text field
656      *
657      * @param array $current new definition
658      * @param array  $previous old definition
659      * @return array  containg all changes that will need to be applied
660      * @access protected
661      */
662     function _compareTextDefinition($current, $previous)
663     {
664         $change = array();
665         $previous_length = array_key_exists('length', $previous) ? $previous['length'] : 0;
666         $length = array_key_exists('length', $current) ? $current['length'] : 0;
667         if ($previous_length != $length) {
668             $change['length'] = true;
669         }
670         return $change;
671     }
672
673     // }}}
674     // {{{ _compareCLOBDefinition()
675
676     /**
677      * Obtain an array of changes that may need to applied to an CLOB field
678      *
679      * @param array $current new definition
680      * @param array  $previous old definition
681      * @return array  containg all changes that will need to be applied
682      * @access protected
683      */
684     function _compareCLOBDefinition($current, $previous)
685     {
686         return $this->_compareTextDefinition($current, $previous);
687     }
688
689     // }}}
690     // {{{ _compareBLOBDefinition()
691
692     /**
693      * Obtain an array of changes that may need to applied to an BLOB field
694      *
695      * @param array $current new definition
696      * @param array  $previous old definition
697      * @return array  containg all changes that will need to be applied
698      * @access protected
699      */
700     function _compareBLOBDefinition($current, $previous)
701     {
702         return $this->_compareTextDefinition($current, $previous);
703     }
704
705     // }}}
706     // {{{ _compareDateDefinition()
707
708     /**
709      * Obtain an array of changes that may need to applied to an date field
710      *
711      * @param array $current new definition
712      * @param array  $previous old definition
713      * @return array  containg all changes that will need to be applied
714      * @access protected
715      */
716     function _compareDateDefinition($current, $previous)
717     {
718         return array();
719     }
720
721     // }}}
722     // {{{ _compareTimeDefinition()
723
724     /**
725      * Obtain an array of changes that may need to applied to an time field
726      *
727      * @param array $current new definition
728      * @param array  $previous old definition
729      * @return array  containg all changes that will need to be applied
730      * @access protected
731      */
732     function _compareTimeDefinition($current, $previous)
733     {
734         return array();
735     }
736
737     // }}}
738     // {{{ _compareTimestampDefinition()
739
740     /**
741      * Obtain an array of changes that may need to applied to an timestamp field
742      *
743      * @param array $current new definition
744      * @param array  $previous old definition
745      * @return array  containg all changes that will need to be applied
746      * @access protected
747      */
748     function _compareTimestampDefinition($current, $previous)
749     {
750         return array();
751     }
752
753     // }}}
754     // {{{ _compareBooleanDefinition()
755
756     /**
757      * Obtain an array of changes that may need to applied to an boolean field
758      *
759      * @param array $current new definition
760      * @param array  $previous old definition
761      * @return array  containg all changes that will need to be applied
762      * @access protected
763      */
764     function _compareBooleanDefinition($current, $previous)
765     {
766         return array();
767     }
768
769     // }}}
770     // {{{ _compareFloatDefinition()
771
772     /**
773      * Obtain an array of changes that may need to applied to an float field
774      *
775      * @param array $current new definition
776      * @param array  $previous old definition
777      * @return array  containg all changes that will need to be applied
778      * @access protected
779      */
780     function _compareFloatDefinition($current, $previous)
781     {
782         return array();
783     }
784
785     // }}}
786     // {{{ _compareDecimalDefinition()
787
788     /**
789      * Obtain an array of changes that may need to applied to an decimal field
790      *
791      * @param array $current new definition
792      * @param array  $previous old definition
793      * @return array  containg all changes that will need to be applied
794      * @access protected
795      */
796     function _compareDecimalDefinition($current, $previous)
797     {
798         return array();
799     }
800
801     // }}}
802     // {{{ quote()
803
804     /**
805      * Convert a text value into a DBMS specific format that is suitable to
806      * compose query statements.
807      *
808      * @param string $value text string value that is intended to be converted.
809      * @param string $type type to which the value should be converted to
810      * @return string text string that represents the given argument value in
811      *       a DBMS specific format.
812      * @access public
813      */
814     function quote($value, $type = null, $quote = true)
815     {
816         $db =& $this->getDBInstance();
817         if (PEAR::isError($db)) {
818             return $db;
819         }
820
821         if (is_null($value)
822             || ($value === '' && $db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)
823         ) {
824             if (!$quote) {
825                 return null;
826             }
827             return 'NULL';
828         }
829
830         if (is_null($type)) {
831             switch (gettype($value)) {
832             case 'integer':
833                 $type = 'integer';
834                 break;
835             case 'double':
836                 // todo
837                 $type = 'decimal';
838                 $type = 'float';
839                 break;
840             case 'boolean':
841                 $type = 'boolean';
842                 break;
843             case 'array':
844             case 'object':
845                  $type = 'text';
846                 break;
847             default:
848                 if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $value)) {
849                     $type = 'timestamp';
850                 } elseif (preg_match('/^\d{2}:\d{2}$/', $value)) {
851                     $type = 'time';
852                 } elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
853                     $type = 'date';
854                 } else {
855                     $type = 'text';
856                 }
857                 break;
858             }
859         }
860
861         if (!method_exists($this, "_quote{$type}")) {
862             return $db->raiseError('type not defined: '.$type);
863         }
864         $value = $this->{"_quote{$type}"}($value);
865
866         // ugly hack to remove single quotes
867         if (!$quote && isset($value[0]) && $value[0] === "'") {
868             $value = substr($value, 1, -1);
869         }
870
871         return $value;
872     }
873
874     // }}}
875     // {{{ _quoteInteger()
876
877     /**
878      * Convert a text value into a DBMS specific format that is suitable to
879      * compose query statements.
880      *
881      * @param string $value text string value that is intended to be converted.
882      * @return string text string that represents the given argument value in
883      *       a DBMS specific format.
884      * @access protected
885      */
886     function _quoteInteger($value)
887     {
888         return (int)$value;
889     }
890
891     // }}}
892     // {{{ _quoteText()
893
894     /**
895      * Convert a text value into a DBMS specific format that is suitable to
896      * compose query statements.
897      *
898      * @param string $value text string value that is intended to be converted.
899      * @return string text string that already contains any DBMS specific
900      *       escaped character sequences.
901      * @access protected
902      */
903     function _quoteText($value)
904     {
905         $db =& $this->getDBInstance();
906         if (PEAR::isError($db)) {
907             return $db;
908         }
909
910         return "'".$db->escape($value)."'";
911     }
912
913     // }}}
914     // {{{ _readFile()
915
916     /**
917      * Convert a text value into a DBMS specific format that is suitable to
918      * compose query statements.
919      *
920      * @param  $value
921      * @return string text string that represents the given argument value in
922      *       a DBMS specific format.
923      * @access protected
924      */
925     function _readFile($value)
926     {
927         $close = false;
928         if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
929             $close = true;
930             if ($match[1] == 'file://') {
931                 $value = $match[2];
932             }
933             $value = @fopen($value, 'r');
934         }
935
936         if (is_resource($value)) {
937             $db =& $this->getDBInstance();
938             if (PEAR::isError($db)) {
939                 return $db;
940             }
941
942             $fp = $value;
943             $value = '';
944             while (!@feof($fp)) {
945                 $value.= @fread($fp, $db->options['lob_buffer_length']);
946             }
947             if ($close) {
948                 @fclose($fp);
949             }
950         }
951
952         return $value;
953     }
954
955     // }}}
956     // {{{ _quoteLOB()
957
958     /**
959      * Convert a text value into a DBMS specific format that is suitable to
960      * compose query statements.
961      *
962      * @param  $value
963      * @return string text string that represents the given argument value in
964      *       a DBMS specific format.
965      * @access protected
966      */
967     function _quoteLOB($value)
968     {
969         $value = $this->_readFile($value);
970         return $this->_quoteText($value);
971     }
972
973     // }}}
974     // {{{ _quoteCLOB()
975
976     /**
977      * Convert a text value into a DBMS specific format that is suitable to
978      * compose query statements.
979      *
980      * @param  $value
981      * @return string text string that represents the given argument value in
982      *       a DBMS specific format.
983      * @access protected
984      */
985     function _quoteCLOB($value)
986     {
987         return $this->_quoteLOB($value);
988     }
989
990     // }}}
991     // {{{ _quoteBLOB()
992
993     /**
994      * Convert a text value into a DBMS specific format that is suitable to
995      * compose query statements.
996      *
997      * @param  $value
998      * @return string text string that represents the given argument value in
999      *       a DBMS specific format.
1000      * @access protected
1001      */
1002     function _quoteBLOB($value)
1003     {
1004         return $this->_quoteLOB($value);
1005     }
1006
1007     // }}}
1008     // {{{ _quoteBoolean()
1009
1010     /**
1011      * Convert a text value into a DBMS specific format that is suitable to
1012      * compose query statements.
1013      *
1014      * @param string $value text string value that is intended to be converted.
1015      * @return string text string that represents the given argument value in
1016      *       a DBMS specific format.
1017      * @access protected
1018      */
1019     function _quoteBoolean($value)
1020     {
1021         return ($value ? "'Y'" : "'N'");
1022     }
1023
1024     // }}}
1025     // {{{ _quoteDate()
1026
1027     /**
1028      * Convert a text value into a DBMS specific format that is suitable to
1029      * compose query statements.
1030      *
1031      * @param string $value text string value that is intended to be converted.
1032      * @return string text string that represents the given argument value in
1033      *       a DBMS specific format.
1034      * @access protected
1035      */
1036     function _quoteDate($value)
1037     {
1038        return $this->_quoteText($value);
1039     }
1040
1041     // }}}
1042     // {{{ _quoteTimestamp()
1043
1044     /**
1045      * Convert a text value into a DBMS specific format that is suitable to
1046      * compose query statements.
1047      *
1048      * @param string $value text string value that is intended to be converted.
1049      * @return string text string that represents the given argument value in
1050      *       a DBMS specific format.
1051      * @access protected
1052      */
1053     function _quoteTimestamp($value)
1054     {
1055        return $this->_quoteText($value);
1056     }
1057
1058     // }}}
1059     // {{{ _quoteTime()
1060
1061     /**
1062      * Convert a text value into a DBMS specific format that is suitable to
1063      *       compose query statements.
1064      *
1065      * @param string $value text string value that is intended to be converted.
1066      * @return string text string that represents the given argument value in
1067      *       a DBMS specific format.
1068      * @access protected
1069      */
1070     function _quoteTime($value)
1071     {
1072        return $this->_quoteText($value);
1073     }
1074
1075     // }}}
1076     // {{{ _quoteFloat()
1077
1078     /**
1079      * Convert a text value into a DBMS specific format that is suitable to
1080      * compose query statements.
1081      *
1082      * @param string $value text string value that is intended to be converted.
1083      * @return string text string that represents the given argument value in
1084      *       a DBMS specific format.
1085      * @access protected
1086      */
1087     function _quoteFloat($value)
1088     {
1089        return $this->_quoteText($value);
1090     }
1091
1092     // }}}
1093     // {{{ _quoteDecimal()
1094
1095     /**
1096      * Convert a text value into a DBMS specific format that is suitable to
1097      * compose query statements.
1098      *
1099      * @param string $value text string value that is intended to be converted.
1100      * @return string text string that represents the given argument value in
1101      *       a DBMS specific format.
1102      * @access protected
1103      */
1104     function _quoteDecimal($value)
1105     {
1106        return $this->_quoteText($value);
1107     }
1108
1109     // }}}
1110     // {{{ writeLOBToFile()
1111
1112     /**
1113      * retrieve LOB from the database
1114      *
1115      * @param resource $lob stream handle
1116      * @param string $file name of the file into which the LOb should be fetched
1117      * @return mixed MDB2_OK on success, a MDB2 error on failure
1118      * @access protected
1119      */
1120     function writeLOBToFile($lob, $file)
1121     {
1122         $db =& $this->getDBInstance();
1123         if (PEAR::isError($db)) {
1124             return $db;
1125         }
1126
1127         $fp = fopen($file, 'wb');
1128         while (!feof($lob)) {
1129             $result = fread($lob, $db->options['lob_buffer_length']);
1130             $read = strlen($result);
1131             if (fwrite($fp, $result, $read) != $read) {
1132                 fclose($fp);
1133                 return $db->raiseError(MDB2_ERROR, null, null,
1134                     'writeLOBToFile: could not write to the output file');
1135             }
1136         }
1137         fclose($fp);
1138         return MDB2_OK;
1139     }
1140
1141     // }}}
1142     // {{{ _retrieveLOB()
1143
1144     /**
1145      * retrieve LOB from the database
1146      *
1147      * @param resource $lob stream handle
1148      * @return mixed MDB2_OK on success, a MDB2 error on failure
1149      * @access protected
1150      */
1151     function _retrieveLOB(&$lob)
1152     {
1153         if (is_null($lob['value'])) {
1154             $lob['value'] = $lob['ressource'];
1155         }
1156         return MDB2_OK;
1157     }
1158
1159     // }}}
1160     // {{{ readLOB()
1161
1162     /**
1163      * Read data from large object input stream.
1164      *
1165      * @param resource $lob stream handle
1166      * @param string $data reference to a variable that will hold data
1167      *                          to be read from the large object input stream
1168      * @param integer $length    value that indicates the largest ammount ofdata
1169      *                          to be read from the large object input stream.
1170      * @return mixed the effective number of bytes read from the large object
1171      *                      input stream on sucess or an MDB2 error object.
1172      * @access public
1173      * @see endOfLOB()
1174      */
1175     function _readLOB($lob, $length)
1176     {
1177         return substr($lob['value'], $lob['position'], $length);
1178     }
1179
1180     // }}}
1181     // {{{ _endOfLOB()
1182
1183     /**
1184      * Determine whether it was reached the end of the large object and
1185      * therefore there is no more data to be read for the its input stream.
1186      *
1187      * @param resource $lob stream handle
1188      * @return mixed true or false on success, a MDB2 error on failure
1189      * @access protected
1190      */
1191     function _endOfLOB($lob)
1192     {
1193         return $lob['endOfLOB'];
1194     }
1195
1196     // }}}
1197     // {{{ destroyLOB()
1198
1199     /**
1200      * Free any resources allocated during the lifetime of the large object
1201      * handler object.
1202      *
1203      * @param resource $lob stream handle
1204      * @access public
1205      */
1206     function destroyLOB($lob)
1207     {
1208         $lob_data = stream_get_meta_data($lob);
1209         $lob_index = $lob_data['wrapper_data']->lob_index;
1210         fclose($lob);
1211         if (isset($this->lobs[$lob_index])) {
1212             $this->_destroyLOB($lob_index);
1213             unset($this->lobs[$lob_index]);
1214         }
1215         return MDB2_OK;
1216     }
1217
1218     // }}}
1219     // {{{ _destroyLOB()
1220
1221     /**
1222      * Free any resources allocated during the lifetime of the large object
1223      * handler object.
1224      *
1225      * @param int $lob_index from the lob array
1226      * @access private
1227      */
1228     function _destroyLOB($lob_index)
1229     {
1230         return MDB2_OK;
1231     }
1232
1233     // }}}
1234     // {{{ implodeArray()
1235
1236     /**
1237      * apply a type to all values of an array and return as a comma seperated string
1238      * useful for generating IN statements
1239      *
1240      * @access public
1241      *
1242      * @param array $array data array
1243      * @param string $type determines type of the field
1244      *
1245      * @return string comma seperated values
1246      */
1247     function implodeArray($array, $type = false)
1248     {
1249         if (!is_array($array) || empty($array)) {
1250             return 'NULL';
1251         }
1252         if ($type) {
1253             foreach ($array as $value) {
1254                 $return[] = $this->quote($value, $type);
1255             }
1256         } else {
1257             $return = $array;
1258         }
1259         return implode(', ', $return);
1260     }
1261 }
1262
1263 ?>