thomascube
2006-02-22 745b1466fc76d5ded589e2469328086002430c1c
commit | author | age
c9462d 1 <?php
S 2 // vim: set et ts=4 sw=4 fdm=marker:
3 // +----------------------------------------------------------------------+
4 // | PHP versions 4 and 5                                                 |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1998-2004 Manuel Lemos, Tomas V.V.Cox,                 |
7 // | Stig. S. Bakken, Lukas Smith                                         |
8 // | All rights reserved.                                                 |
9 // +----------------------------------------------------------------------+
10 // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
11 // | API as well as database abstraction for PHP applications.            |
12 // | This LICENSE is in the BSD license style.                            |
13 // |                                                                      |
14 // | Redistribution and use in source and binary forms, with or without   |
15 // | modification, are permitted provided that the following conditions   |
16 // | are met:                                                             |
17 // |                                                                      |
18 // | Redistributions of source code must retain the above copyright       |
19 // | notice, this list of conditions and the following disclaimer.        |
20 // |                                                                      |
21 // | Redistributions in binary form must reproduce the above copyright    |
22 // | notice, this list of conditions and the following disclaimer in the  |
23 // | documentation and/or other materials provided with the distribution. |
24 // |                                                                      |
25 // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
26 // | Lukas Smith nor the names of his contributors may be used to endorse |
27 // | or promote products derived from this software without specific prior|
28 // | written permission.                                                  |
29 // |                                                                      |
30 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
31 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
32 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
33 // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
34 // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
35 // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
36 // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
37 // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
38 // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
39 // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
40 // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
41 // | POSSIBILITY OF SUCH DAMAGE.                                          |
42 // +----------------------------------------------------------------------+
43 // | Author: Lukas Smith <smith@pooteeweet.org>                           |
44 // |         Lorenzo Alberton <l.alberton@quipo.it>                       |
45 // +----------------------------------------------------------------------+
46 //
47 // $Id$
48
49 require_once 'MDB2/Driver/Datatype/Common.php';
50
51 /**
52  * MDB2 Firebird/Interbase driver
53  *
54  * @package MDB2
55  * @category Database
56  * @author  Lukas Smith <smith@pooteeweet.org>
57  * @author  Lorenzo Alberton <l.alberton@quipo.it>
58  */
59 class MDB2_Driver_Datatype_ibase extends MDB2_Driver_Datatype_Common
60 {
61     // {{{ convertResult()
62
63     /**
64      * convert a value to a RDBMS independent MDB2 type
65      *
66      * @param mixed  $value   value to be converted
67      * @param int    $type    constant that specifies which type to convert to
68      * @return mixed converted value or a MDB2 error on failure
69      * @access public
70      */
71     function convertResult($value, $type)
72     {
73         if (is_null($value)) {
74             return null;
75         }
76         $db =& $this->getDBInstance();
77         if (PEAR::isError($db)) {
78             return $db;
79         }
80
81         switch ($type) {
82         case 'decimal':
83             return sprintf('%.'.$db->options['decimal_places'].'f', doubleval($value)/pow(10.0, $db->options['decimal_places']));
84         case 'timestamp':
85             return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
86         default:
87             return $this->_baseConvertResult($value, $type);
88         }
89     }
90
91     // }}}
92     // {{{ getTypeDeclaration()
93
94     /**
95      * Obtain DBMS specific SQL code portion needed to declare an text type
96      * field to be used in statements like CREATE TABLE.
97      *
98      * @param array $field  associative array with the name of the properties
99      *      of the field being declared as array indexes. Currently, the types
100      *      of supported field properties are as follows:
101      *
102      *      length
103      *          Integer value that determines the maximum length of the text
104      *          field. If this argument is missing the field should be
105      *          declared to have the longest length allowed by the DBMS.
106      *
107      *      default
108      *          Text value to be used as default for this field.
109      *
110      *      notnull
111      *          Boolean flag that indicates whether this field is constrained
112      *          to not be set to null.
113      * @return string  DBMS specific SQL code portion that should be used to
114      *      declare the specified field.
115      * @access public
116      */
117     function getTypeDeclaration($field)
118     {
119         $db =& $this->getDBInstance();
120         if (PEAR::isError($db)) {
121             return $db;
122         }
123
124         switch ($field['type']) {
125         case 'text':
126             $length = (array_key_exists('length', $field) ? $field['length'] : (!PEAR::isError($length = $db->options['default_text_field_length']) ? $length : 4000));
127             return 'VARCHAR ('.$length.')';
128         case 'clob':
129             return 'BLOB SUB_TYPE 1';
130         case 'blob':
131             return 'BLOB SUB_TYPE 0';
132         case 'integer':
133             return 'INTEGER';
134         case 'boolean':
135             return 'CHAR (1)';
136         case 'date':
137             return 'DATE';
138         case 'time':
139             return 'TIME';
140         case 'timestamp':
141             return 'TIMESTAMP';
142         case 'float':
143             return 'DOUBLE PRECISION';
144         case 'decimal':
145             return 'DECIMAL(18,'.$db->options['decimal_places'].')';
146         }
147         return '';
148     }
149
150     // }}}
151     // {{{ _getIntegerDeclaration()
152
153     /**
154      * Obtain DBMS specific SQL code portion needed to declare an integer type
155      * field to be used in statements like CREATE TABLE.
156      *
157      * @param string $name name the field to be declared.
158      * @param array $field associative array with the name of the properties
159      *       of the field being declared as array indexes. Currently, the types
160      *       of supported field properties are as follows:
161      *
162      *       unsigned
163      *           Boolean flag that indicates whether the field should be
164      *           declared as unsigned integer if possible.
165      *
166      *       default
167      *           Integer value to be used as default for this field.
168      *
169      *       notnull
170      *           Boolean flag that indicates whether this field is constrained
171      *           to not be set to null.
172      * @return string DBMS specific SQL code portion that should be used to
173      *       declare the specified field.
174      * @access protected
175      */
176     function _getIntegerDeclaration($name, $field)
177     {
178         if (array_key_exists('unsigned', $field) && $field['unsigned']) {
179             $db =& $this->getDBInstance();
180             if (PEAR::isError($db)) {
181                 return $db;
182             }
183             $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
184         }
185
186         if (array_key_exists('autoincrement', $field) && $field['autoincrement']) {
187             return $name.' PRIMARY KEY';
188         }
189
190         $default = array_key_exists('default', $field) ? ' DEFAULT '.
191             $this->quote($field['default'], 'integer') : '';
192         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
193         return $name.' INT'.$default.$notnull;
194     }
195
196     // }}}
197     // {{{ _getTextDeclaration()
198
199     /**
200      * Obtain DBMS specific SQL code portion needed to declare a text type
201      * field to be used in statements like CREATE TABLE.
202      *
203      * @param string $name   name the field to be declared.
204      * @param array  $field  associative array with the name of the properties
205      *      of the field being declared as array indexes. Currently, the types
206      *      of supported field properties are as follows:
207      *
208      *      length
209      *          Integer value that determines the maximum length of the text
210      *          field. If this argument is missing the field should be
211      *          declared to have the longest length allowed by the DBMS.
212      *
213      *      default
214      *          Text value to be used as default for this field.
215      *
216      *      notnull
217      *          Boolean flag that indicates whether this field is constrained
218      *          to not be set to null.
219      * @return string  DBMS specific SQL code portion that should be used to
220      *      declare the specified field.
221      * @access protected
222      */
223     function _getTextDeclaration($name, $field)
224     {
225         $type = $this->getTypeDeclaration($field);
226         $default = array_key_exists('default', $field) ? ' DEFAULT '.
227             $this->quote($field['default'], 'text') : '';
228         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
229         return $name.' '.$type.$default.$notnull;
230     }
231
232     // }}}
233     // {{{ _getCLOBDeclaration()
234
235     /**
236      * Obtain DBMS specific SQL code portion needed to declare a character
237      * large object type field to be used in statements like CREATE TABLE.
238      *
239      * @param string $name   name the field to be declared.
240      * @param array $field  associative array with the name of the properties
241      *      of the field being declared as array indexes. Currently, the types
242      *      of supported field properties are as follows:
243      *
244      *      length
245      *          Integer value that determines the maximum length of the large
246      *          object field. If this argument is missing the field should be
247      *          declared to have the longest length allowed by the DBMS.
248      *
249      *      notnull
250      *          Boolean flag that indicates whether this field is constrained
251      *          to not be set to null.
252      * @return string  DBMS specific SQL code portion that should be used to
253      *      declare the specified field.
254      * @access protected
255      */
256     function _getCLOBDeclaration($name, $field)
257     {
258         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
259         return $name.' '.$this->getTypeDeclaration($field).$notnull;
260     }
261
262     // }}}
263     // {{{ _getBLOBDeclaration()
264
265     /**
266      * Obtain DBMS specific SQL code portion needed to declare a binary large
267      * object type field to be used in statements like CREATE TABLE.
268      *
269      * @param string $name   name the field to be declared.
270      * @param array $field  associative array with the name of the properties
271      *      of the field being declared as array indexes. Currently, the types
272      *      of supported field properties are as follows:
273      *
274      *      length
275      *          Integer value that determines the maximum length of the large
276      *          object field. If this argument is missing the field should be
277      *          declared to have the longest length allowed by the DBMS.
278      *
279      *      notnull
280      *          Boolean flag that indicates whether this field is constrained
281      *          to not be set to null.
282      * @return string  DBMS specific SQL code portion that should be used to
283      *      declare the specified field.
284      * @access protected
285      */
286     function _getBLOBDeclaration($name, $field)
287     {
288         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
289         return $name.' '.$this->getTypeDeclaration($field).$notnull;
290     }
291
292     // }}}
293     // {{{ _getDateDeclaration()
294
295     /**
296      * Obtain DBMS specific SQL code portion needed to declare a date type
297      * field to be used in statements like CREATE TABLE.
298      *
299      * @param string $name   name the field to be declared.
300      * @param array $field  associative array with the name of the properties
301      *      of the field being declared as array indexes. Currently, the types
302      *      of supported field properties are as follows:
303      *
304      *      default
305      *          Date value to be used as default for this field.
306      *
307      *      notnull
308      *          Boolean flag that indicates whether this field is constrained
309      *          to not be set to null.
310      * @return string  DBMS specific SQL code portion that should be used to
311      *      declare the specified field.
312      * @access protected
313      */
314     function _getDateDeclaration($name, $field)
315     {
316         $default = array_key_exists('default', $field) ? ' DEFAULT '.
317             $this->quote($field['default'], 'date') : '';
318         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
319         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
320     }
321
322     // }}}
323     // {{{ _getTimeDeclaration()
324
325     /**
326      * Obtain DBMS specific SQL code portion needed to declare a time
327      * field to be used in statements like CREATE TABLE.
328      *
329      * @param string $name   name the field to be declared.
330      * @param array $field  associative array with the name of the properties
331      *      of the field being declared as array indexes. Currently, the types
332      *      of supported field properties are as follows:
333      *
334      *      default
335      *          Time value to be used as default for this field.
336      *
337      *      notnull
338      *          Boolean flag that indicates whether this field is constrained
339      *          to not be set to null.
340      * @return string  DBMS specific SQL code portion that should be used to
341      *      declare the specified field.
342      * @access protected
343      */
344     function _getTimeDeclaration($name, $field)
345     {
346         $default = array_key_exists('default', $field) ? ' DEFAULT '.
347             $this->quote($field['default'], 'time') : '';
348         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
349         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
350     }
351
352     // }}}
353     // {{{ _getTimestampDeclaration()
354
355     /**
356      * Obtain DBMS specific SQL code portion needed to declare a timestamp
357      * field to be used in statements like CREATE TABLE.
358      *
359      * @param string  $name   name the field to be declared.
360      * @param array   $field  associative array with the name of the properties
361      *       of the field being declared as array indexes. Currently, the types
362      *       of supported field properties are as follows:
363      *
364      *       default
365      *           Timestamp value to be used as default for this field.
366      *
367      *       notnull
368      *           Boolean flag that indicates whether this field is constrained
369      *           to not be set to null.
370      * @return string  DBMS specific SQL code portion that should be used to
371      *                 declare the specified field.
372      * @access protected
373      */
374     function _getTimestampDeclaration($name, $field)
375     {
376         $default = array_key_exists('default', $field) ? ' DEFAULT '.
377             $this->quote($field['default'], 'timestamp') : '';
378         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
379         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
380     }
381
382     // }}}
383     // {{{ _getFloatDeclaration()
384
385     /**
386      * Obtain DBMS specific SQL code portion needed to declare a float type
387      * field to be used in statements like CREATE TABLE.
388      *
389      * @param string $name   name the field to be declared.
390      * @param array $field  associative array with the name of the properties
391      *      of the field being declared as array indexes. Currently, the types
392      *      of supported field properties are as follows:
393      *
394      *      default
395      *          Float value to be used as default for this field.
396      *
397      *      notnull
398      *          Boolean flag that indicates whether this field is constrained
399      *          to not be set to null.
400      * @return string  DBMS specific SQL code portion that should be used to
401      *      declare the specified field.
402      * @access protected
403      */
404     function _getFloatDeclaration($name, $field)
405     {
406         $default = array_key_exists('default', $field) ? ' DEFAULT '.
407             $this->quote($field['default'], 'float') : '';
408         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
409         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
410     }
411
412     // }}}
413     // {{{ _getDecimalDeclaration()
414
415     /**
416      * Obtain DBMS specific SQL code portion needed to declare a decimal type
417      * field to be used in statements like CREATE TABLE.
418      *
419      * @param string $name   name the field to be declared.
420      * @param array $field  associative array with the name of the properties
421      *      of the field being declared as array indexes. Currently, the types
422      *      of supported field properties are as follows:
423      *
424      *      default
425      *          Decimal value to be used as default for this field.
426      *
427      *      notnull
428      *          Boolean flag that indicates whether this field is constrained
429      *          to not be set to null.
430      * @return string  DBMS specific SQL code portion that should be used to
431      *      declare the specified field.
432      * @access protected
433      */
434     function _getDecimalDeclaration($name, $field)
435     {
436         $default = array_key_exists('default', $field) ? ' DEFAULT '.
437             $this->quote($field['default'], 'decimal') : '';
438         $notnull = (array_key_exists('notnull', $field) && $field['notnull']) ? ' NOT NULL' : '';
439         return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
440     }
441
442     // }}}
443     // {{{ _quoteLOB()
444
445     /**
446      * Convert a text value into a DBMS specific format that is suitable to
447      * compose query statements.
448      *
449      * @param  $value
450      * @return string text string that represents the given argument value in
451      *      a DBMS specific format.
452      * @access protected
453      */
454     function _quoteLOB($value)
455     {
456         $db =& $this->getDBInstance();
457         if (PEAR::isError($db)) {
458             return $db;
459         }
460
461         if (PEAR::isError($connect = $db->connect())) {
462             return $connect;
463         }
464         $close = true;
465         if (is_resource($value)) {
466             $close = false;
467         } elseif (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
468             if ($match[1] == 'file://') {
469                 $value = $match[2];
470             }
471             $value = @fopen($value, 'r');
472         } else {
473             $fp = @tmpfile();
474             @fwrite($fp, $value);
475             @rewind($fp);
476             $value = $fp;
477         }
478         if ($db->in_transaction) {
479             $blob_id = @ibase_blob_import($db->transaction_id, $value);
480         } else {
481             $blob_id = @ibase_blob_import($db->connection, $value);
482         }
483         if ($close) {
484             @fclose($value);
485         }
486         return $blob_id;
487     }
488
489     // }}}
490     // {{{ _quoteDecimal()
491
492     /**
493      * Convert a text value into a DBMS specific format that is suitable to
494      * compose query statements.
495      *
496      * @param string $value text string value that is intended to be converted.
497      * @return string text string that represents the given argument value in
498      *      a DBMS specific format.
499      * @access protected
500      */
501     function _quoteDecimal($value)
502     {
503         $db =& $this->getDBInstance();
504         if (PEAR::isError($db)) {
505             return $db;
506         }
507
508         return (strval(round($value*pow(10.0, $db->options['decimal_places']))));
509     }
510
511     // }}}
512     // {{{ _retrieveLOB()
513
514     /**
515      * retrieve LOB from the database
516      *
517      * @param resource $lob stream handle
518      * @return mixed MDB2_OK on success, a MDB2 error on failure
519      * @access protected
520      */
521     function _retrieveLOB(&$lob)
522     {
523         if (!array_key_exists('handle', $lob)) {
524             $lob['handle'] = @ibase_blob_open($lob['ressource']);
525             if (!$lob['handle']) {
526                 $db =& $this->getDBInstance();
527                 if (PEAR::isError($db)) {
528                     return $db;
529                 }
530
531                 return $db->raiseError(MDB2_ERROR, null, null,
532                     '_retrieveLOB: Could not open fetched large object field' . @ibase_errmsg());
533             }
534         }
535         return MDB2_OK;
536     }
537
538     // }}}
539     // {{{ _readLOB()
540
541     /**
542      * Read data from large object input stream.
543      *
544      * @param resource $lob stream handle
545      * @param blob $data reference to a variable that will hold data to be
546      *      read from the large object input stream
547      * @param int $length integer value that indicates the largest ammount of
548      *      data to be read from the large object input stream.
549      * @return mixed length on success, a MDB2 error on failure
550      * @access protected
551      */
552     function _readLOB($lob, $length)
553     {
554         $data = ibase_blob_get($lob['handle'], $length);
555         if (!is_string($data)) {
556             $db =& $this->getDBInstance();
557             if (PEAR::isError($db)) {
558                 return $db;
559             }
560
561             return $db->raiseError(MDB2_ERROR, null, null,
562                 'Read Result LOB: ' . @ibase_errmsg());
563         }
564         return $data;
565     }
566
567     // }}}
568     // {{{ _destroyLOB()
569
570     /**
571      * Free any resources allocated during the lifetime of the large object
572      * handler object.
573      *
574      * @param resource $lob stream handle
575      * @access protected
576      */
577     function _destroyLOB($lob_index)
578     {
579         if (isset($this->lobs[$lob_index]['handle'])) {
580            @ibase_blob_close($this->lobs[$lob_index]['handle']);
581         }
582     }
583
584     // }}}
585     // {{{ mapNativeDatatype()
586
587     /**
588      * Maps a native array description of a field to a MDB2 datatype and length
589      *
590      * @param array  $field native field description
591      * @return array containing the various possible types and the length
592      * @access public
593      */
594     function mapNativeDatatype($field)
595     {
596         $db_type = preg_replace('/\d/','', strtolower($field['typname']) );
597         $length = $field['attlen'];
598         if ($length == '-1') {
599             $length = $field['atttypmod']-4;
600         }
601         if ((int)$length <= 0) {
602             $length = null;
603         }
604         $type = array();
605         switch ($db_type) {
606         case 'smallint':
607         case 'integer':
608             $type[] = 'integer';
609             if ($length == '1') {
610                 $type[] = 'boolean';
611             }
612             break;
613         case 'char':
614         case 'varchar':
615             $type[] = 'text';
616             if ($length == '1') {
617                 $type[] = 'boolean';
618             }
619             break;
620         case 'date':
621             $type[] = 'date';
622             $length = null;
623             break;
624         case 'timestamp':
625             $type[] = 'timestamp';
626             $length = null;
627             break;
628         case 'time':
629             $type[] = 'time';
630             $length = null;
631             break;
632         case 'float':
633         case 'double precision':
634             $type[] = 'float';
635             break;
636         case 'decimal':
637         case 'numeric':
638             $type[] = 'decimal';
639             break;
640         case 'blob':
641             $type[] = 'blob';
642             $length = null;
643             break;
644         default:
645             $db =& $this->getDBInstance();
646             if (PEAR::isError($db)) {
647                 return $db;
648             }
649
650             return $db->raiseError(MDB2_ERROR, null, null,
651                 'getTableFieldDefinition: unknown database attribute type');
652         }
653
654         return array($type, $length);
655     }
656
657     // }}}
658 }
659 ?>