commit | author | age
|
b7e7c8
|
1 |
#!/usr/bin/env php |
AM |
2 |
<?php |
|
3 |
/* |
|
4 |
+-----------------------------------------------------------------------+ |
|
5 |
| bin/updatedb.sh | |
|
6 |
| | |
|
7 |
| This file is part of the Roundcube Webmail client | |
|
8 |
| Copyright (C) 2010-2012, The Roundcube Dev Team | |
|
9 |
| Copyright (C) 2010-2012, Kolab Systems AG | |
|
10 |
| | |
|
11 |
| Licensed under the GNU General Public License version 3 or | |
|
12 |
| any later version with exceptions for skins & plugins. | |
|
13 |
| See the README file for a full license statement. | |
|
14 |
| | |
|
15 |
| PURPOSE: | |
|
16 |
| Update database schema | |
|
17 |
+-----------------------------------------------------------------------+ |
|
18 |
| Author: Aleksander Machniak <alec@alec.pl> | |
|
19 |
+-----------------------------------------------------------------------+ |
|
20 |
*/ |
|
21 |
|
|
22 |
define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); |
|
23 |
|
|
24 |
require_once INSTALL_PATH . 'program/include/clisetup.php'; |
|
25 |
|
|
26 |
// get arguments |
|
27 |
$opts = rcube_utils::get_opt(array( |
|
28 |
'v' => 'version', |
|
29 |
'd' => 'dir', |
9e329c
|
30 |
'p' => 'package', |
b7e7c8
|
31 |
)); |
AM |
32 |
|
|
33 |
if (empty($opts['dir'])) { |
f23ef1
|
34 |
rcube::raise_error("Database schema directory not specified (--dir).", false, true); |
b7e7c8
|
35 |
} |
9e329c
|
36 |
if (empty($opts['package'])) { |
f23ef1
|
37 |
rcube::raise_error("Database schema package name not specified (--package).", false, true); |
b7e7c8
|
38 |
} |
AM |
39 |
|
|
40 |
// Check if directory exists |
|
41 |
if (!file_exists($opts['dir'])) { |
f23ef1
|
42 |
rcube::raise_error("Specified database schema directory doesn't exist.", false, true); |
b7e7c8
|
43 |
} |
AM |
44 |
|
7e7431
|
45 |
$RC = rcube::get_instance(); |
AM |
46 |
$DB = rcube_db::factory($RC->config->get('db_dsnw')); |
|
47 |
|
|
48 |
// Connect to database |
|
49 |
$DB->db_connect('w'); |
|
50 |
if (!$DB->is_connected()) { |
f23ef1
|
51 |
rcube::raise_error("Error connecting to database: " . $DB->is_error(), false, true); |
7e7431
|
52 |
} |
AM |
53 |
|
c10187
|
54 |
// Read DB schema version from database (if 'system' table exists) |
15e4c8
|
55 |
if (in_array($DB->table_name('system'), (array)$DB->list_tables())) { |
9be085
|
56 |
$DB->query("SELECT " . $DB->quote_identifier('value') |
c10187
|
57 |
." FROM " . $DB->quote_identifier($DB->table_name('system')) |
9be085
|
58 |
." WHERE " . $DB->quote_identifier('name') ." = ?", |
9e329c
|
59 |
$opts['package'] . '-version'); |
7e7431
|
60 |
|
9be085
|
61 |
$row = $DB->fetch_array(); |
9e46fb
|
62 |
$version = preg_replace('/[^0-9]/', '', $row[0]); |
9be085
|
63 |
} |
7e7431
|
64 |
|
9be085
|
65 |
// DB version not found, but release version is specified |
7e7431
|
66 |
if (!$version && $opts['version']) { |
b7e7c8
|
67 |
// Map old release version string to DB schema version |
AM |
68 |
// Note: This is for backward compat. only, do not need to be updated |
|
69 |
$map = array( |
|
70 |
'0.1-stable' => 1, |
|
71 |
'0.1.1' => 2008030300, |
|
72 |
'0.2-alpha' => 2008040500, |
|
73 |
'0.2-beta' => 2008060900, |
|
74 |
'0.2-stable' => 2008092100, |
|
75 |
'0.3-stable' => 2008092100, |
|
76 |
'0.3.1' => 2009090400, |
|
77 |
'0.4-beta' => 2009103100, |
|
78 |
'0.4.2' => 2010042300, |
|
79 |
'0.5-beta' => 2010100600, |
|
80 |
'0.5' => 2010100600, |
|
81 |
'0.5.1' => 2010100600, |
|
82 |
'0.6-beta' => 2011011200, |
|
83 |
'0.6' => 2011011200, |
|
84 |
'0.7-beta' => 2011092800, |
|
85 |
'0.7' => 2011111600, |
|
86 |
'0.7.1' => 2011111600, |
|
87 |
'0.7.2' => 2011111600, |
|
88 |
'0.7.3' => 2011111600, |
c2c1bb
|
89 |
'0.7.4' => 2011111600, |
b7e7c8
|
90 |
'0.8-beta' => 2011121400, |
AM |
91 |
'0.8-rc' => 2011121400, |
|
92 |
'0.8.0' => 2011121400, |
|
93 |
'0.8.1' => 2011121400, |
|
94 |
'0.8.2' => 2011121400, |
|
95 |
'0.8.3' => 2011121400, |
|
96 |
'0.8.4' => 2011121400, |
c2c1bb
|
97 |
'0.8.5' => 2011121400, |
AM |
98 |
'0.8.6' => 2011121400, |
b7e7c8
|
99 |
'0.9-beta' => 2012080700, |
AM |
100 |
); |
|
101 |
|
|
102 |
$version = $map[$opts['version']]; |
|
103 |
} |
|
104 |
|
c10187
|
105 |
// Assume last version before the 'system' table was added |
b7e7c8
|
106 |
if (empty($version)) { |
AM |
107 |
$version = 2012080700; |
|
108 |
} |
|
109 |
|
|
110 |
$dir = $opts['dir'] . DIRECTORY_SEPARATOR . $DB->db_provider; |
|
111 |
if (!file_exists($dir)) { |
f23ef1
|
112 |
rcube::raise_error("DDL Upgrade files for " . $DB->db_provider . " driver not found.", false, true); |
b7e7c8
|
113 |
} |
AM |
114 |
|
|
115 |
$dh = opendir($dir); |
|
116 |
$result = array(); |
|
117 |
|
|
118 |
while ($file = readdir($dh)) { |
|
119 |
if (preg_match('/^([0-9]+)\.sql$/', $file, $m) && $m[1] > $version) { |
|
120 |
$result[] = $m[1]; |
|
121 |
} |
|
122 |
} |
|
123 |
sort($result, SORT_NUMERIC); |
|
124 |
|
|
125 |
foreach ($result as $v) { |
|
126 |
echo "Updating database schema ($v)... "; |
9e329c
|
127 |
$error = update_db_schema($opts['package'], $v, $dir . DIRECTORY_SEPARATOR . "$v.sql"); |
b7e7c8
|
128 |
|
AM |
129 |
if ($error) { |
f23ef1
|
130 |
echo "[FAILED]\n"; |
AM |
131 |
rcube::raise_error("Error in DDL upgrade $v: $error", false, true); |
b7e7c8
|
132 |
} |
AM |
133 |
echo "[OK]\n"; |
|
134 |
} |
|
135 |
|
|
136 |
|
9e329c
|
137 |
function update_db_schema($package, $version, $file) |
b7e7c8
|
138 |
{ |
AM |
139 |
global $DB; |
|
140 |
|
|
141 |
// read DDL file |
|
142 |
if ($lines = file($file)) { |
|
143 |
$sql = ''; |
|
144 |
foreach ($lines as $line) { |
|
145 |
if (preg_match('/^--/', $line) || trim($line) == '') |
|
146 |
continue; |
|
147 |
|
|
148 |
$sql .= $line . "\n"; |
|
149 |
if (preg_match('/(;|^GO)$/', trim($line))) { |
15e4c8
|
150 |
@$DB->query(fix_table_names($sql)); |
b7e7c8
|
151 |
$sql = ''; |
AM |
152 |
if ($error = $DB->is_error()) { |
|
153 |
return $error; |
|
154 |
} |
|
155 |
} |
|
156 |
} |
|
157 |
} |
|
158 |
|
c3d061
|
159 |
// escape if 'system' table does not exist |
AM |
160 |
if ($version < 2013011000) { |
|
161 |
return; |
|
162 |
} |
|
163 |
|
c10187
|
164 |
$system_table = $DB->quote_identifier($DB->table_name('system')); |
AM |
165 |
|
|
166 |
$DB->query("UPDATE " . $system_table |
b7e7c8
|
167 |
." SET " . $DB->quote_identifier('value') . " = ?" |
AM |
168 |
." WHERE " . $DB->quote_identifier('name') . " = ?", |
9e329c
|
169 |
$version, $package . '-version'); |
b7e7c8
|
170 |
|
AM |
171 |
if (!$DB->is_error() && !$DB->affected_rows()) { |
c10187
|
172 |
$DB->query("INSERT INTO " . $system_table |
b7e7c8
|
173 |
." (" . $DB->quote_identifier('name') . ", " . $DB->quote_identifier('value') . ")" |
AM |
174 |
." VALUES (?, ?)", |
9e329c
|
175 |
$package . '-version', $version); |
b7e7c8
|
176 |
} |
AM |
177 |
|
|
178 |
return $DB->is_error(); |
|
179 |
} |
|
180 |
|
15e4c8
|
181 |
function fix_table_names($sql) |
TB |
182 |
{ |
399db1
|
183 |
global $DB, $RC, $dir; |
AM |
184 |
static $tables; |
|
185 |
static $sequences; |
15e4c8
|
186 |
|
399db1
|
187 |
$prefix = $RC->config->get('db_prefix'); |
AM |
188 |
$engine = $DB->db_provider; |
|
189 |
|
|
190 |
if (empty($prefix)) { |
|
191 |
return $sql; |
|
192 |
} |
|
193 |
|
|
194 |
if ($tables === null) { |
|
195 |
$tables = array(); |
|
196 |
$sequences = array(); |
|
197 |
|
|
198 |
// read complete schema (initial) file |
|
199 |
$filename = "$dir/../$engine.initial.sql"; |
|
200 |
$schema = @file_get_contents($filename); |
|
201 |
|
|
202 |
// find table names |
|
203 |
if (preg_match_all('/CREATE TABLE (\[dbo\]\.|IF NOT EXISTS )?[`"\[\]]*([^`"\[\] \r\n]+)/i', $schema, $matches)) { |
|
204 |
foreach ($matches[2] as $table) { |
|
205 |
$tables[$table] = $prefix . $table; |
|
206 |
} |
15e4c8
|
207 |
} |
399db1
|
208 |
// find sequence names |
AM |
209 |
if ($engine == 'postgres' && preg_match_all('/CREATE SEQUENCE (IF NOT EXISTS )?"?([^" \n\r]+)/i', $schema, $matches)) { |
|
210 |
foreach ($matches[2] as $sequence) { |
|
211 |
$sequences[$sequence] = $prefix . $sequence; |
|
212 |
} |
|
213 |
} |
|
214 |
} |
|
215 |
|
|
216 |
// replace table names |
|
217 |
foreach ($tables as $table => $real_table) { |
|
218 |
$sql = preg_replace("/([^a-zA-Z0-9_])$table([^a-zA-Z0-9_])/", "\\1$real_table\\2", $sql); |
|
219 |
} |
|
220 |
// replace sequence names |
|
221 |
foreach ($sequences as $sequence => $real_sequence) { |
|
222 |
$sql = preg_replace("/([^a-zA-Z0-9_])$sequence([^a-zA-Z0-9_])/", "\\1$real_sequence\\2", $sql); |
15e4c8
|
223 |
} |
TB |
224 |
|
|
225 |
return $sql; |
|
226 |
} |
|
227 |
|
b7e7c8
|
228 |
?> |