Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 106
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
IacSqlInfo
0.00% covered (danger)
0.00%
0 / 106
0.00% covered (danger)
0.00%
0 / 5
2352
0.00% covered (danger)
0.00%
0 / 1
 result2fields
0.00% covered (danger)
0.00%
0 / 80
0.00% covered (danger)
0.00%
0 / 1
1260
 charsetnr2chars
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 type2Text
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 flags2Array
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 constantsFill
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * IacSqlInfo
4 * Provides meta data and information on sql statements and database
5 *
6 * @package sql
7 * @author Informatica Asociada
8 * @copyright 2015
9 * @version 1.0.0
10 * @require php 5.3
11 */
12/*
13
14create table vacia(
15abigint1 bigint,
16abigint1u bigint unsigned,
17aint1 int,
18aint1u int unsigned not null,
19amediumint1 mediumint,
20amediumint1u mediumint unsigned,
21asmallint1 smallint,
22asmallint1u smallint unsigned not null,
23atinyint1 tinyint,
24atinyint1u tinyint unsigned not null,
25ayear4 year(4) COMMENT '1901 to 2155 o 0000 for invalid',
26
27
28adecimal5_2 DECIMAL(5,2) not null default '0.00' COMMENT ' -999.99 to 999.99',
29adecimal5_2u DECIMAL(5,2) unsigned not null default '0.00',
30anumeric5_2 NUMERIC(5,2) not null default '0.00',
31anumeric5_2u NUMERIC(5,2) unsigned not null default '0.00',
32
33anumeric3_0 NUMERIC(3,0) not null default '0',
34anumeric3_0u NUMERIC(3,0) unsigned not null default '0',
35anumeric3 NUMERIC(3) not null default '0',
36anumeric3u NUMERIC(3) unsigned not null default '0',
37
38afloat7_4 FLOAT(7,4) not null default '0.00' COMMENT 'ie  -999.9999',
39afloat7_4u FLOAT(7,4) unsigned not null default '0.00',
40
41adouble7_4 DOUBLE(7,4) not null default '0.00' COMMENT 'ie  -999.9999',
42adouble7_4u DOUBLE(7,4) unsigned not null default '0.00',
43
44areal7_4 REAL(7,4) not null default '0.00' COMMENT 'ie  -999.9999',
45areal7_4u REAL(7,4) unsigned not null default '0.00',
46
47adouble3_0 DOUBLE(3,0) not null default '0' COMMENT ' no decs',
48adouble3_0u DOUBLE(3,0) unsigned not null default '0',
49
50
51abti1 bit(1),
52abti16 bit(16),
53
54adate date COMMENT '1000-01-01 to 9999-12-31 ',
55adatetime datetime COMMENT '1000-01-01 to 9999-12-31 fractional seconds part in up to microseconds (6 digits) as of MySQL 5.6.4 prev ignored',
56atimestamp timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '1970-01-01 00:00:01 UTC to 2038-01-19 03:14:07 UTC  fractional seconds part in up to microseconds (6 digits) as of MySQL 5.6.4 prev ignored',
57
58
59achar4 char(4),
60avarchar129 varchar(129),
61abinary12 binary(12),
62avarbinary12 varbinary(12),
63
64atinytext tinytext,
65atext text,
66amediumtext mediumtext,
67alongtext longtext,
68
69atinyblob tinyblob,
70ablob blob,
71amediumblob mediumblob,
72alongblob longblob,
73
74geo geometry, pt point, ln linestring, poly polygon,
75
76geo_coll geometrycollection, pt_multi multipoint, ln_multi multilinestring, poly_multi multipolygon
77
78--ayear2 year(2) COMMENT '1 to 99, depreciated, creates year4!',
79
80)
81
82*/
83
84namespace Iac\inc\sql;
85
86/**
87 * IacSqlInfo
88 *
89 * @author Informatica Asociada
90 * @copyright 2015
91 * @version 1.0.0
92 * @require php 5.3
93 */
94class IacSqlInfo {
95    protected $flags;
96    protected $types;
97
98    protected $apiType2mysql = array(
99        'bigint'=> 'longlong',
100        'int'=> 'long',
101        'mediumint'=> 'int24',
102        'smallint'=> 'short',
103        'tinyint'=> 'tinyint',
104        'year'=> 'year',
105        'numeric'=> 'decimal',
106
107    );
108
109    // https://dev.mysql.com/doc/refman/5.5/en/integer-types.html
110    protected $dataTypesUnsigned = array(
111        'tinyint'=>array('max'=>255),
112        'smallint'=>array('max'=>65535),
113        'mediumint'=>array('max'=>16777215),
114        'int'=>array('max'=>4294967295),
115        'bigint'=>array('max'=>'18446744073709551615'),
116        'year' => array('max'=>2155,'min'=>1901),
117    );
118
119
120    protected $dataTypesTrans = array(
121        'tinyint'=>array('type'=>'tinyint', 'numeric'=>true,'bytes'=>1, 'min'=>-128, 'max'=>127,),
122
123        'decimal' => array( 'type'=>'decimal', 'numeric'=>true, 'floatingPoint'=>true,
124            ),
125        'char' => array( 'type'=>'char',
126            ),
127        'short' => array( 'type'=>'smallint', 'numeric'=>true,'bytes'=>2, 'min'=>-32768, 'max'=>32767,
128            ),
129        'long' => array( 'type'=>'int', 'numeric'=>true,'bytes'=>4, 'min'=>-2147483648, 'max'=>2147483647,
130            ),
131        'float' => array( 'type'=>'float', 'numeric'=>true, 'floatingPoint'=>true,
132            ),
133        'double' => array( 'type'=>'double', 'numeric'=>true, 'floatingPoint'=>true,
134            ),
135        'null' => array( 'type'=>'null',
136            ),
137        'timestamp' => array( 'type'=>'timestamp',
138            ),
139        'longlong' => array( 'type'=>'bigint', 'numeric'=>true,'bytes'=>8, 'min'=>'-9223372036854775808', 'max'=>'9223372036854775807',
140            ),
141        'int24' => array( 'type'=>'mediumint', 'numeric'=>true,'bytes'=>3, 'min'=>-8388608, 'max'=>8388607,
142            ),
143        'date' => array( 'type'=>'date',
144            ),
145        'time' => array( 'type'=>'time',
146            ),
147        'datetime' => array( 'type'=>'datetime',
148            ),
149        'year' => array( 'type'=>'year', 'numeric'=>true,
150            ),
151        'newdate' => array( 'type'=>'date',
152            ),
153        'interval' => array( 'type'=>'interval',
154            ),
155        'set' => array( 'type'=>'set',
156            ),
157        'tiny_blob' => array( 'type'=>'tinytext', 'blob'=>true,
158            ),
159        'medium_blob' => array( 'type'=>'mediumtext', 'blob'=>true,
160            ),
161        'long_blob' => array( 'type'=>'longtext', 'blob'=>true,
162            ),
163        'blob' => array( 'type'=>'text', 'blob'=>true,
164            ),
165        'var_string' => array( 'type'=>'varchar',
166            ),
167        'string' => array( 'type'=>'binary',
168            ),
169        'geometry' => array( 'type'=>'geometry',
170            ),
171        'newdecimal' => array( 'type'=>'decimal', 'numeric'=>true, 'floatingPoint'=>true,
172            ),
173        'bit' => array( 'type'=>'bit',
174            ),
175    );
176// Art 60 risr deduccion casa habitacion por uso o goce, depositos efvo regla 3.5.11
177    /**
178     * IacSqlInfo::result2fields()
179     *
180     * @param object $result mysqli resultset
181     * @return array associative array indexed by field with field's metadata
182     */
183    public function result2fields($result) {
184        $primary_keys = 0;
185        $fields = array();
186        $finfo = $result->fetch_fields();
187        foreach ($finfo as $f) {
188            $binary = ($f->flags & MYSQLI_BINARY_FLAG) === MYSQLI_BINARY_FLAG;
189
190            $asMysqli = $type = $this->type2Text($f->type,$f->flags);
191            // mysqli type to mysql data type
192
193            //if(($f->flags & MYSQLI_GROUP_FLAG) && $asMysqli === 'CHAR')
194            if($f->charsetnr === 63 && $asMysqli === 'CHAR')
195                $type = 'TINYINT';
196            elseif(($f->flags & MYSQLI_ENUM_FLAG) === MYSQLI_ENUM_FLAG)
197                $type = 'ENUM';
198            elseif(($f->flags & MYSQLI_SET_FLAG) === MYSQLI_SET_FLAG)
199                $type = 'SET';
200            elseif(!$binary && $asMysqli === 'STRING')
201                $type = 'CHAR';
202            elseif($binary && $asMysqli === 'VAR_STRING')
203                $type = "VARBINARY";
204            $type = strtolower($type);
205            if(array_key_exists($type, $this->apiType2mysql))
206                $type = $this->apiType2mysql[$type];
207
208            $field = array(
209                'type' => strtolower($type),
210                'typeMysqli' => $asMysqli,
211                'flags' => $this->flags2Array($f->flags),
212                'metaData' => $f,
213                //'max_chars' => $f->length, // ?
214            );
215
216           if(($f->flags & MYSQLI_PRI_KEY_FLAG) === MYSQLI_PRI_KEY_FLAG) {
217                $primary_keys++;
218                $field['pri_key'] = true;
219                $field['pri_key_multiple'] = $primary_keys > 1; // on multi coolumn primar key the first column will be fixed after this loop
220                $field['auto_increment'] = ($f->flags & MYSQLI_AUTO_INCREMENT_FLAG) === MYSQLI_AUTO_INCREMENT_FLAG;
221           }
222           $field['null'] = !( ($f->flags & MYSQLI_NOT_NULL_FLAG) === MYSQLI_NOT_NULL_FLAG );
223           $field['required'] = !$field['null'];
224
225            if(isset($this->dataTypesTrans[$type]))
226                $field = array_merge($field,$this->dataTypesTrans[$type]);
227            $type = $field['type'];
228
229            if($type === 'char' || $type === 'varchar' || $type === 'binary' || $type === 'varbinary') {
230                $field['max_chars'] = $this->charsetnr2chars($f->length,$f->charsetnr);
231                $field['max_multibytes'] = $f->length;
232            }
233            elseif(isset($field['numeric'])) {
234                $unsigned = ($f->flags & MYSQLI_UNSIGNED_FLAG) === MYSQLI_UNSIGNED_FLAG;
235                $field['decimals'] = $f->decimals;
236                if(isset($field['floatingPoint'])) {
237                    if($f->decimals == 0) {
238                        $decs = '';
239                        if($type==='decimal') {
240                            if($unsigned) {
241                                $integers = $field['integers'] = $f->length - $f->decimals;
242                            } else {
243                                $integers = $field['integers'] = $f->length - $f->decimals -1;
244                            }
245                        } else {
246                            $integers = $field['integers'] = $f->length - $f->decimals;
247                        }
248                    } else {
249                        $decs = '.'.str_repeat('9',$f->decimals);
250                        if($type==='decimal') {
251                            if($unsigned) {
252                                $integers = $field['integers'] = $f->length - $f->decimals -1;
253                            } else {
254                                $integers = $field['integers'] = $f->length - $f->decimals -2;
255                            }
256                        } else {
257                            $integers = $field['integers'] = $f->length - $f->decimals;
258                        }
259                    }
260                    $field['min'] = '-'.str_repeat('9',$integers).$decs;
261                    $field['max'] = str_repeat('9',$integers).$decs;
262                } else {
263                    if($unsigned) {
264                        $field['integers'] = $f->length - $f->decimals;
265                    } else {
266                        $field['integers'] = $f->length - $f->decimals - 1;
267                    }
268                }
269                if($unsigned) {
270                    $field['min'] = 0;
271                    if(isset($this->dataTypesUnsigned[$type]))
272                        $field = array_merge($field,$this->dataTypesUnsigned[$type]);
273                    $field['max_chars'] = strlen($field['max']);
274                } else {
275                    $field['max_chars'] = strlen($field['min']);
276                }
277            }
278            elseif(isset($field['blob'])) {
279                if($binary)
280                    $field['type'] = str_replace('text','blob',$field['type']);
281                if($f->length > 0) {
282                    $field['max_multibytes'] = $f->length;
283                    if(!$binary)
284                        $field['max_chars'] = $this->charsetnr2chars($f->length,$f->charsetnr);
285                }
286            }
287            elseif($type === 'bit') {
288                $field['min'] = 0;
289                $field['max'] = $f->length; //FIXME
290                $field['max_chars'] = $f->length;
291            }
292           $fields[$f->name] = $field;
293        }
294        // on multiple column primary key, mark the first column as multiple
295        if($primary_keys > 1)
296            foreach($fields as &$field)
297                if(isset($field['pri_key'])) {
298                    $field['pri_key_multiple'] = true;
299                    break;
300                }
301        return $fields;
302    }
303
304    /**
305     * IacSqlInfo::charsetnr2chars()
306     * Returns length in characters given the length in bytes, for the given $charsetnr
307     *
308     * @param int $lengthInBytes length in  bytes
309     * @param int $charsetnr mysql characterset code
310     * @return int
311     */
312    protected function charsetnr2chars($lengthInBytes,$charsetnr) {
313        if($charsetnr == 33) // utf8
314            return $lengthInBytes/3;
315        if($charsetnr == 8) // latin1
316            return $lengthInBytes;
317        //TODO SELECT * FROM information_schema.collations;
318        return $lengthInBytes;
319    }
320
321    /**
322     * iacMysqli::type2Text()
323     * return mysqli type for the field
324     *
325     * @param integer $type_id from $result->fetch_field()->type or $result->fetch_field_direct($i)->type
326     * @return string mysql type for id
327     */
328    public function type2Text($type_id,$flags_num) {
329        // fill constants if not done yet
330        $this->constantsFill();
331        // unkown type
332        if(!array_key_exists($type_id, $this->types))
333            return null;
334        return $this->types[$type_id];
335    }
336
337    /**
338     * iacMysqli::flags2Array()
339     * Get mysqli flags
340     *
341     * @param integer $flags_num from $result->fetch_field()->flags or $result->fetch_field_direct($i)->flags
342     * @return array associative array with flag names indexed by mysqli constant
343     */
344    public function flags2Array($flags_num) {
345        // fill constants if not done yet
346        //if(!isset($this->flags))
347        $this->constantsFill();
348        $result = array();
349        foreach($this->flags as $n => $t)
350            if(($flags_num & $n) === $n) {
351                $result[$n] = $t;
352            }
353        return $result;
354    }
355
356    /**
357     * IacSqlInfo::constantsFill()
358     * Fills mysqli's type names into $this->types and flag names into $this>$flags
359     *
360     * @return void
361     * @see http://php.net/manual/en/mysqli-result.fetch-fields.php
362     * @see http://php.net/manual/en/mysqli.constants.php
363     */
364    protected function constantsFill() {
365        if(isset($this->types)) {
366            return; // constants have been filled
367        }
368        $flags = array();
369        $types = array();
370        $constants = get_defined_constants(true); // era true
371        foreach($constants['mysqli'] as $c => $n)
372            if(preg_match('/^MYSQLI_TYPE_(.*)/', $c, $m))
373                $types[$n] = $m[1];
374            elseif(preg_match('/MYSQLI_(.*)_FLAG$/', $c, $mFlag))
375                $flags[$n] = $mFlag[1];
376        $this->types = $types;
377        $this->flags = $flags;
378    }
379
380}