4 require_once dirname(__FILE__).'/../www/env.inc.php';
5 require_once $gfwww.'include/pre.php';
8 * Sets up CLI environment based on SAPI and PHP version
10 if (version_compare(phpversion(), '4.3.0', '<') || php_sapi_name() == 'cgi') {
11 // Handle output buffering
13 ob_implicit_flush(TRUE);
17 ini_set('track_errors', TRUE);
18 ini_set('html_errors', FALSE);
19 ini_set('magic_quotes_runtime', FALSE);
21 // Define stream constants
22 define('STDIN', fopen('php://stdin', 'r'));
23 define('STDOUT', fopen('php://stdout', 'w'));
24 define('STDERR', fopen('php://stderr', 'w'));
26 // Close the streams on script termination
27 register_shutdown_function(
29 'fclose(STDIN); fclose(STDOUT); fclose(STDERR); return true;')
33 $db_path = dirname(__FILE__).'/';
37 // a huge message will warn not to run it without doing a backup first // warning.
39 // Check if table 'database_startpoint' exists
40 $res = db_query_params ('SELECT COUNT(*) AS proceed FROM pg_class WHERE relname = $1 AND relkind = $2',
41 array('database_startpoint',
44 if (!$res) { // db error
45 show("DB-ERROR-2: ".db_error()."\n");
48 $proceed = db_result($res, 0, 'proceed');
49 if (!$proceed) { // table does not exist
50 show("ERROR: table 'database_startpoint' does not exist.\nRun startpoint.php first.\n");
53 // Check if table 'database_startpoint' has proper values
54 $res = db_query_params ('SELECT * FROM database_startpoint',
57 if (!$res) { // db error
58 show("DB-ERROR-3: ".db_error()."\n");
60 } else if (db_numrows($res) == 0) { // table 'database_startpoint' is empty
61 show("ERROR: table 'database_startpoint' is empty.\nRun startpoint.php first.\n");
63 } else { // get the start date from the db
64 $date = (int) db_result($res, 0, 'db_start_date');
65 $version = db_result($res, 0, 'db_version');
70 if (!apply_fixes($version)) {
71 show("ERROR applying fixes to version $version!\n");
75 $scripts = get_scripts($db_path);
77 foreach ($scripts as $script) {
78 if ((int) $script['date'] > $date) {
79 $res = db_query_params ('SELECT * FROM database_changes WHERE filename=$1',
80 array ("{$script['filename']}")) ;
83 show("ERROR-2: ".db_error()."\n");
85 } else if (db_numrows($res) == 0) {
86 show("Running script: {$script['filename']}\n");
87 $result = run_script($script);
89 $res = db_query_params ('INSERT INTO database_changes (filename) VALUES ($1)',
90 array ("{$script['filename']}")) ;
93 show("ERROR-3: ".db_error()."\n");
101 show("Skipping script: {$script['filename']}\n");
106 function get_scripts($dir) {
109 if ($dh = opendir($dir)) {
110 while (($file = readdir($dh)) !== false) {
111 $pos = strrpos($file, '.');
112 if ($pos !== false && $pos > 0) {
113 $name = substr($file, 0, $pos);
114 if (strlen($name) >= 8) {
115 $date_aux = substr($name, 0, 8);
116 $type_aux = substr($file, $pos + 1);
117 if ((int) $date_aux > 20000000 && ($type_aux=='sql' || $type_aux=='php') && strpos($file, 'debian') === false) {
118 $data[] = array('date'=>$date_aux, 'filename'=>$file, 'ext'=>$type_aux);
125 usort($data, 'compare_scripts');
132 function compare_scripts($script1, $script2) {
133 return strcmp($script1['filename'], $script2['filename']);
136 function run_script($script) {
140 $ext = strtolower($script['ext']);
141 $filename = $script['filename'];
143 // run the php script
145 $exec = 'php -f '.$db_path.$filename;
146 exec($exec, $result);
148 if (count($result)) { // the script produced an output
149 if ($result[count($result)-1] == 'SUCCESS') {
150 show($db_path.$filename." ran correctly\n\n");
153 show($db_path.$filename." FAILED!\n\n");
154 foreach ($result as $line) {
159 show($db_path.$filename." FAILED!\n\n");
162 } else if ($ext == 'sql') {
163 if (//$filename == '20021124-3_gforge-debian-sf-sync.sql' ||
164 $filename == '20021223-drops.sql') {
166 echo "\nskipping $filename";
169 // run the sql script
171 if (run_sql_script($filename)) {
172 show($db_path.$filename." ran correctly\n\n");
175 show($db_path.$filename." FAILED!\n\n");
179 // something went wrong
180 show("\nThe script is not a PHP file nor an SQL file. Something went wrong. Please report this bug\n");
185 function run_sql_script($filename) {
188 $sql_file = $db_path.$filename;
189 $file = @fopen($sql_file, 'rb');
193 $content = fread($file, filesize($sql_file));
196 $content = preg_replace("/--(.*)/", '', $content);
198 $parts = explode(";\n", $content);
201 $is_function = false;
202 $is_copy_stdin = false;
204 for ($i=0;$i<count($parts);$i++) {
206 // Check if it's a function
207 if ((in_string($q, 'create function') || in_string($q, 'create or replace function') ||
208 in_string($q, 'replace function')) && !in_string($q, 'language plpgsql') &&
209 !in_string($q, 'language \'plpgsql\'')&& !in_string($q, 'language \'c\'') &&
210 !in_string($q, 'language c')) {
212 while (!in_string($q, 'language plpgsql') && !in_string($q, 'language \'plpgsql\'')) {
214 $q = $q.';'.$parts[$i];
216 $queries[] = trim($q);
217 // Check if it is a COPY FROM stdin
218 } else if (in_string($q, 'copy') && in_string($q, 'from stdin')) {
219 while (!in_string($q, '\.')) {
221 $q = $q.";\n".$parts[$i];
223 $aux = explode('\.', $q, 2);
224 $queries[] = ltrim($aux[0]."\\.\n");
225 if (trim($aux[1]) != '') {
226 $queries[] = trim($aux[1]);
228 // Else, we just add it up
230 if (trim($q) != '') {
231 $queries[] = trim(preg_replace("/\s+/", ' ', str_replace("\n", ' ', $q)));
240 foreach ($queries as $query) {
241 // Check if it is a DROP TABLE
242 if (in_string($query, 'drop table')) {
243 $aux = explode(' ', trim($query));
244 if (count($aux) == 3 || count($aux) == 4) { // PERFECT!
245 drop_table_if_exists($aux[2], (count($aux) == 4) && preg_match('/CASCADE/i', trim($aux[3])));
249 // Check if it is a DROP SEQUENCE
250 } else if (in_string($query, 'drop sequence')) {
251 $aux = explode(' ', trim($query));
252 if (count($aux) == 3) { // PERFECT!
253 drop_seq_if_exists($aux[2]);
257 // Check if it is a DROP TRIGGER
258 } else if (in_string($query, 'drop trigger')) {
259 $aux = explode(' ', trim($query));
260 if (count($aux) == 5 || count($aux) == 6) { // PERFECT!
261 drop_trigger_if_exists($aux[2], $aux[4]);
265 // Check if it is a DROP VIEW
266 } else if (in_string($query, 'drop view')) {
267 $aux = explode(' ', trim($query));
268 if (count($aux) == 3 || count($aux) == 4) { // PERFECT!
269 drop_view_if_exists($aux[2]);
273 // Check if it is a DROP INDEX
274 } else if (in_string($query, 'drop index')) {
275 $aux = explode(' ', trim($query));
276 if (count($aux) == 3 || count($aux) == 4) { // PERFECT!
277 drop_index_if_exists($aux[2]);
281 // Check if it is a DROP CONSTRAINT
282 } else if (in_string($query, 'alter table') && in_string($query, 'drop constraint')) {
283 $aux = explode(' ', trim($query));
284 $table = trim($aux[2], "\" ");
285 $constraint = trim($aux[5], "\" ");
287 drop_constraint_if_exists($table, $constraint, $query);
289 $res = db_query($query);
291 show(db_error()."\n");
292 show("QUERY: $query\n");
293 show("Continue executing ([Y]es/[N]o)?\n");
295 $answer = strtolower(trim(fgets(STDIN)));
296 if ($answer != 'y' && $answer != 'yes') {
307 // Patch for some 3.0preX versions
308 if ($filename == '20021216.sql') {
309 db_query_params ('SELECT setval($1, (SELECT MAX(theme_id) FROM themes), true)',
310 array('themes_theme_id_key')) ;
312 show("Applying fix for some 3.0preX versions\n");
319 function apply_fixes($version) {
321 if ($version == 'sfee3.3') {
322 $res = db_query_params('SELECT COUNT(*) AS applied FROM database_changes WHERE filename=$1', array ('sfee3.3fixes')) ;
323 if ($res && db_result($res, 0, 'applied') == '0') {
324 show("Converting SFEE3.3 to SFEE3.0\n");
325 run_script(array('filename'=>'sfee3.3-3.0-1.sql','ext'=>'sql'));
326 run_script(array('filename'=>'sfee3.3-3.0-2.php','ext'=>'php'));
327 run_script(array('filename'=>'sfee3.3-3.0-3.sql','ext'=>'sql'));
328 show("Converting SFEE3.0 to SF2.6\n");
330 run_script(array('filename'=>'sfee3.0-sf26-1.sql','ext'=>'sql'));
331 run_script(array('filename'=>'sfee3.0-sf26-2.php','ext'=>'php'));
332 $queries[] = "INSERT INTO database_changes (filename) VALUES ('sfee3.3fixes')";
334 } else if ($version == 'sfee3.0') {
335 $res = db_query_params ('SELECT COUNT(*) AS applied FROM database_changes WHERE filename=$1',
336 array ('sfee3.0fixes')) ;
337 if ($res && db_result($res, 0, 'applied') == '0') {
338 run_script(array('filename'=>'sfee3.0-sf26-1.sql','ext'=>'sql'));
339 run_script(array('filename'=>'sfee3.0-sf26-2.php','ext'=>'php'));
340 $queries[] = "INSERT INTO database_changes (filename) VALUES ('sfee3.0fixes')";
342 } else if ($version == '2.5') {
343 $res = db_query_params ('SELECT COUNT(*) AS applied FROM database_changes WHERE filename=$1',
345 if ($res && db_result($res, 0, 'applied') == '0') {
346 show("Applying fixes for version 2.5\n");
347 $queries[] = "ALTER TABLE project_task ADD CONSTRAINT project_task_group_project_id_f CHECK (1 = 1)";
348 $queries[] = "INSERT INTO database_changes (filename) VALUES ('2.5fixes')";
350 } else if ($version == '2.6') {
351 $res = db_query_params ('SELECT COUNT(*) AS applied FROM database_changes WHERE filename=$1',
352 array ('2.6fixes')) ;
353 if ($res && db_result($res, 0, 'applied') == '0') {
354 show("Applying fixes for version 2.6\n");
355 $queries[] = "ALTER TABLE project_task ADD CONSTRAINT project_task_group_project_id_f CHECK (1 = 1)";
356 $queries[] = "INSERT INTO database_changes (filename) VALUES ('2.6fixes')";
358 } else if ($version == '3.0pre5') {
359 $res = db_query_params ('SELECT COUNT(*) AS applied FROM database_changes WHERE filename=$1',
360 array ('3.0pre5fixes')) ;
361 if ($res && db_result($res, 0, 'applied') == '0') {
362 show("Applying fixes for version 3.0pre5\n");
363 if (!run_sql_script('fix-gforge3.0pre5.sql')) {
364 show("Error applying fixes for version 3.0pre5\n");
367 $queries[] = "INSERT INTO database_changes (filename) VALUES ('3.0pre5fixes')";
369 } else if ($version == '3.0pre6') {
370 $res = db_query_params ('SELECT COUNT(*) AS applied FROM database_changes WHERE filename=$1', array ('3.0pre6fixes')) ;
371 if ($res && db_result($res, 0, 'applied') == '0') {
372 show("Applying fixes for version 3.0pre6\n");
373 $queries[] = "ALTER TABLE project_task ADD CONSTRAINT project_task_group_project_id_f CHECK (1 = 1)";
374 $queries[] = "INSERT INTO database_changes (filename) VALUES ('3.0pre6fixes')";
376 } else if ($version == '3.0pre7') {
377 $res = db_query_params ('SELECT COUNT(*) AS applied FROM database_changes WHERE filename=$1',
378 array ('3.0pre7fixes')) ;
379 if ($res && db_result($res, 0, 'applied') == '0') {
380 show("Applying fixes for version 3.0pre7\n");
381 $queries[] = "ALTER TABLE project_task ADD CONSTRAINT project_task_group_project_id_f CHECK (1 = 1)";
382 $queries[] = "INSERT INTO database_changes (filename) VALUES ('3.0pre7fixes')";
384 } else if ($version == '4.7') {
385 run_script(array('filename'=>'20070924-project-perm.sql','ext'=>'sql'));
386 run_script(array('filename'=>'20070924-forum-perm.sql','ext'=>'sql'));
387 run_script(array('filename'=>'20070924-artifact-perm.sql','ext'=>'sql'));
391 foreach ($queries as $query) {
392 $res = db_query($query);
394 show("ERROR: ".db_error()."\n");
403 function drop_view_if_exists($name) {
404 $result = drop_if_exists($name, 'DROP VIEW', 'v');
408 function drop_seq_if_exists($name) {
409 $result = drop_if_exists($name, 'DROP SEQUENCE', 'S');
413 function drop_index_if_exists($name) {
414 $result = drop_if_exists($name, 'DROP INDEX', 'i');
418 function drop_table_if_exists($name, $cascade) {
420 $result = drop_if_exists($name, 'DROP TABLE', 'r', 'CASCADE');
422 $result = drop_if_exists($name, 'DROP TABLE', 'r');
427 function drop_if_exists($name, $command, $kind, $commandSuffix = '') {
428 // Strip "name" => name
429 if (preg_match('/^"(.*)"$/', $name, $match)) {
432 $res = db_query_params ('SELECT COUNT(*) AS exists FROM pg_class WHERE relname=$1 AND relkind=$2',
436 show("ERROR:".db_error()."\n");
439 if (db_result($res, 0, 'exists') != '0') {
440 $res = db_query("$command $name $commandSuffix");
442 show("ERROR:".db_error()."\n");
450 function drop_constraint_if_exists($table, $constraint, $query) {
451 $res = db_query_params ('SELECT COUNT(*) AS exists FROM information_schema.constraint_table_usage WHERE table_name=$1 AND constraint_name=$2',
456 show("ERROR:".db_error()."\n");
459 if (db_result($res, 0, 'exists') != '0') {
460 $res = db_query($query);
462 show("ERROR:".db_error()."\n");
468 function drop_trigger_if_exists($name, $on) {
469 $res = db_query_params ('SELECT COUNT(*) AS exists FROM pg_trigger WHERE tgname=$1',
472 show("ERROR:".db_error()."\n");
475 if (db_result($res, 0, 'exists') != '0') {
476 $res = db_query("DROP TRIGGER $name ON $on");
478 show("ERROR:".db_error()."\n");
486 function in_string($haystack, $needle, $case_sensitive = false) {
487 if (!$case_sensitive) {
488 $haystack = strtolower($haystack);
490 if (strpos($haystack, $needle) !== false) {
497 function show($text) {
499 fwrite(STDOUT, $text);
504 // c-file-style: "bsd"