import
[web.mtrack] / bin / data-move.php
1 <?php # vim:ts=2:sw=2:et:
2
3 /* For licensing and copyright terms, see the file named LICENSE */
4
5 if (function_exists('date_default_timezone_set')) {
6   date_default_timezone_set('UTC');
7 }
8 ini_set('memory_limit', -1);
9
10 include_once dirname(__FILE__) . '/../inc/common.php';
11
12 if (count($argv) != 2) {
13   echo "Usage: bin/data-move.php 'pgsql:dbname=foo;user=bar'\n";
14   echo <<<TXT
15 Reads your existing mtrack database (uses DSN information in config.ini).
16 Connects to the specified DSN and creates the mtrack schema, then populates
17 it from your existing mtrack database.
18
19 TXT;
20
21   exit(1);
22 }
23 /* destination DSN */
24 $ddsn = $argv[1];
25
26 $sdsn = MTrackConfig::get('core', 'dsn');
27 if (!$sdsn) {
28   $sdsn = 'sqlite:' . MTrackConfig::get('core', 'dblocation');
29 }
30 $sdb = new PDO($sdsn);
31 $sdb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
32
33 $ddb = new PDO($ddsn);
34 $ddb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
35 $ddb->exec("set client_encoding='utf-8'");
36
37 $driver = $ddb->getAttribute(PDO::ATTR_DRIVER_NAME);
38 $adapter_class = "MTrackDBSchema_$driver";
39 $adapter = new $adapter_class;
40
41 $adapter->setDB($ddb);
42 $vers = $adapter->determineVersion();
43 echo "Version: ";
44 var_dump($vers);
45
46 $ddb->beginTransaction();
47
48 $schemata = array();
49 $latest = null;
50 foreach (glob(dirname(__FILE__) . '/../schema/*.xml') as $filename) {
51   $latest = new MTrackDBSchema($filename);
52   $schemata[$latest->version] = $latest;
53 }
54
55 echo "Applying schema version $latest->version\n";
56 foreach ($latest->tables as $t) {
57   $adapter->createTable($t);
58
59   $names = array();
60
61   foreach ($t->fields as $f) {
62     if ($f->type == 'autoinc') {
63       // Omit: we want the database to set this for us, otherwise
64       // sequence numbers won't get populated!
65       continue;
66     }
67     $names[] = $f->name;
68   }
69   $pull = 'select ' . join(',', $names) . ' from ' . $t->name;
70
71   $push = 'insert into ' . $t->name . '(' . join(',', $names) . ') values (' .
72     str_repeat('?,', count($names) - 1) . '?)';
73
74   $sq = $sdb->query($pull, PDO::FETCH_NUM);
75
76   $dq = $ddb->prepare($push);
77
78   foreach ($sq as $row) {
79     /* postgres has stronger data validation requirements;
80     * fixup the data */
81     $send = array();
82     foreach ($names as $i => $fname) {
83       $f = $t->fields[$fname];
84       switch ($f->type) {
85         case 'integer':
86         case 'autoinc':
87           if ($row[$i] == '') {
88             if (isset($f->nullable) && $f->nullable == '0') {
89               $row[$i] = 0;
90             } else {
91               $row[$i] = null;
92             }
93           }
94           $dq->bindValue(1+$i, $row[$i]);
95           break;
96         case 'real':
97           if ($row[$i] == '') {
98             if (isset($f->nullable) && $f->nullable == '0') {
99               $dq->bindValue(1+$i, 0.0);
100             } else {
101               $dq->bindValue(1+$i, null);
102             }
103           } else {
104             /* avoid converting to double here, for sake of precision.
105              * Also, somehow we have commas in our data... fix that */
106             $dq->bindValue(1+$i, str_replace(",", ".", $row[$i]));
107           }
108           break;
109         case 'blob':
110           if (is_null($row[$i])) {
111             $dq->bindValue(1+$i, null);
112           } else {
113             $stm = fopen('php://memory', 'r+');
114             fwrite($stm, $row[$i]);
115             rewind($stm);
116             $dq->bindValue(1+$i, $stm, PDO::PARAM_LOB);
117           }
118           break;
119         case 'text':
120         default:
121           /* CSV import could have injected non-UTF-8 data */
122           if (is_null($row[$i])) {
123             $dq->bindValue(1+$i, null);
124           } else {
125             $enc = mb_detect_encoding($row[$i], 'UTF-8,ISO-8859-1');
126             if ($enc != 'UTF-8') {
127               $dq->bindValue(1+$i,
128                 mb_convert_encoding($row[$i], 'UTF-8', $enc));
129             } else {
130               $dq->bindValue(1+$i, $row[$i]);
131             }
132           }
133       }
134     }
135     try {
136       $dq->execute();
137     } catch (Exception $e) {
138       echo "$push\n";
139       var_dump($names);
140       var_dump($row);
141       var_dump($send);
142       foreach ($send as $d) {
143         echo bin2hex($d) . "\n";
144       }
145       throw $e;
146     }
147   }
148 }
149 if (isset($latest->post[$driver])) {
150   $ddb->exec($latest->post[$driver]);
151 }
152 $vers = $latest->version;
153
154
155
156
157 $ddb->exec('delete from mtrack_schema');
158 $q = $ddb->prepare('insert into mtrack_schema (version) values (?)');
159 $q->execute(array($latest->version));
160 $ddb->commit();
161
162
163
164