UpdateDatabase/MysqlEngineCharset.php
[Pman.Core] / UpdateDatabase / MysqlEngineCharset.php
1 <?php
2 /**
3   fixes character set and engine=InnoDB.. in Mysql
4   more efficent 
5  */
6
7 class Pman_Core_UpdateDatabase_MysqlEngineCharset {
8     
9     var $dburl;
10     var $schema = array();
11     var $links = array();
12     var $views = array();
13     
14     function __construct()
15     {
16         // this might get run before we have imported the database
17         // and hence not have any db.
18         try {
19             $this->loadIniFiles(); //?? shared???
20         } catch(PDO_DataObject_Exception_InvalidConfig $e) {
21             echo "SKipping MysqlEngineCharse - no database yet\n";
22             return;
23         }
24         
25         $dbo = DB_DataObject::factory('core_enum');
26         if (is_a($dbo, 'PDO_DataObject')) {
27             
28             $this->views = $dbo->generator()->introspection()->getListOf('views');
29         } else {
30             $db = DB_DataObject::factory('core_enum')->getDatabaseConnection();
31             $this->views = $db->getListOf( 'views');  // needs updated pear... 
32         }
33         
34         // update the engine first - get's around 1000 character limit on indexes..cd
35         // however - Innodb does not support fulltext indexes, so this may fail...
36         $this->updateEngine(); 
37         
38         $this->updateCharacterSet();
39         
40         
41     }
42     
43     function loadIniFiles()
44     {
45         // will create the combined ini cache file for the running user.
46         
47         $ff = HTML_FlexyFramework::get();
48         $ff->generateDataobjectsCache(true);
49         $this->dburl = parse_url($ff->database);
50         
51          
52         $dbini = 'ini_'. basename($this->dburl['path']);
53         
54         
55         $iniCache = isset( $ff->PDO_DataObject) ?  $ff->PDO_DataObject['schema_location'] : $ff->DB_DataObject[$dbini];
56         if (!file_exists($iniCache)) {
57             return;
58         }
59         
60         $this->schema = parse_ini_file($iniCache, true);
61         $this->links = parse_ini_file(preg_replace('/\.ini$/', '.links.ini', $iniCache), true);
62         
63
64         
65     }
66    
67     function updateCharacterSet()
68     {
69         $views = $this->views;
70         
71         
72         foreach (array_keys($this->schema) as $tbl){
73             
74             if(strpos($tbl, '__keys') !== false ){
75                 continue;
76             }
77             
78             if(in_array($tbl , $views)) {
79                 continue;
80             }
81             
82             $ce = DB_DataObject::factory('core_enum');
83             
84             $ce->query("
85                 SELECT
86                         CCSA.character_set_name csname,
87                         CCSA.collation_name collatename
88                 FROM
89                         information_schema.`TABLES` T,
90                         information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA
91                 WHERE
92                         CCSA.collation_name = T.table_collation
93                     AND
94                         T.table_schema = DATABASE() -- COLLATE utf8_general_ci
95                     AND
96                         T.table_name = '{$tbl}' -- COLLATE utf8_general_ci
97             ");
98                      
99             if (!$ce->fetch()) {
100                 continue;
101             }
102             
103             if($ce->csname == 'utf8' && $ce->collatename == 'utf8_general_ci'){
104                 echo "utf8: SKIP $tbl\n";
105                 continue;
106             }
107             // this used to be utf8_unicode_ci
108             //as the default collation for stored procedure parameters is utf8_general_ci and you can't mix collations.
109             
110             $ce = DB_DataObject::factory('core_enum');
111             // not sure why, but convert to does not actually change the 'charset=' bit..
112             $ce->query("ALTER TABLE $tbl CHARSET=utf8");
113             $ce->query("ALTER TABLE {$tbl} CONVERT TO CHARACTER SET  utf8 COLLATE utf8_general_ci");
114             echo "utf8: FIXED {$tbl}\n";
115             
116         }
117     }
118     function updateEngine()
119     {
120         $db = DB_DataObject::factory('core_enum');
121         $db->query("show variables like 'innodb_file_per_table'");
122         $db->fetch();
123         
124         $pg = HTML_FlexyFramework::get()->page;
125         
126         if (empty($pg->opts['skip-mysql-checks'])) {
127             if ($db->Value == 'OFF') {
128                 die("Error: set innodb_file_per_table = 1 in my.cnf\n\n");
129             }
130             
131         }
132         
133         
134         // get a list of table views...
135         // innodb in single files is far more efficient that MYD or one big innodb file.
136         // first check if database is using this format.
137         
138         
139         
140         $views = $this->views;
141         
142         
143         foreach (array_keys($this->schema) as $tbl){
144             
145             if(strpos($tbl, '__keys') !== false ){
146                 continue;
147             }
148             
149             if(in_array($tbl , $views)) {
150                 continue;
151             }
152             
153             $ce = DB_DataObject::factory('core_enum');
154             
155             $ce->query("
156                 select
157                     engine
158                 from
159                     information_schema.tables
160                 where
161                     table_schema= DATABASE()
162                     and
163                     table_name = '{$tbl}'
164             ");
165
166             if (!$ce->fetch()) {
167                 continue;
168             }
169             //AWS is returning captials?
170             $engine = isset($ce->engine) ? $ce->engine : $ce->ENGINE;
171             
172             if($engine == 'InnoDB' ){
173                 echo "InnoDB: SKIP $tbl\n";
174                 continue;
175             }
176             if($engine == 'ndbcluster' ){
177                 echo "ndbcluster: SKIP $tbl\n";
178                 continue;
179             }
180             
181             // should really determine if we are running in cluster ready ...
182             
183             // this used to be utf8_unicode_ci
184             //as the default collation for stored procedure parameters is utf8_general_ci and you can't mix collations.
185             
186             $ce = DB_DataObject::factory('core_enum');
187             $ce->query("ALTER TABLE $tbl ENGINE=InnoDB");
188             echo "InnoDB: FIXED {$tbl}\n";
189             
190         }
191     }
192     
193 }
194