upgrade and database_compare combined, database_compare removed. View "belegeregs" removed.

This commit is contained in:
OpenXE 2022-12-06 16:55:31 +00:00
parent 77393c186e
commit ce268dca0e
4 changed files with 891 additions and 343 deletions

View File

@ -26043,168 +26043,7 @@
]
}
]
},
{
"name": "belegeregs",
"type": "VIEW",
"columns": [
{
"Field": "id",
"Type": "int(11)",
"Collation": null,
"Null": "NO",
"Key": "",
"Default": "0",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "adresse",
"Type": "int(11)",
"Collation": null,
"Null": "NO",
"Key": "",
"Default": "0",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "datum",
"Type": "date",
"Collation": null,
"Null": "NO",
"Key": "",
"Default": "0000-00-00",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "belegnr",
"Type": "varchar(255)",
"Collation": "utf8mb3_general_ci",
"Null": "NO",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "status",
"Type": "varchar(64)",
"Collation": "utf8mb3_general_ci",
"Null": "NO",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "land",
"Type": "varchar(255)",
"Collation": "utf8mb3_general_ci",
"Null": "NO",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "typ",
"Type": "varchar(10)",
"Collation": "utf8mb4_general_ci",
"Null": "NO",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "umsatz_netto",
"Type": "decimal(19,2)",
"Collation": null,
"Null": "NO",
"Key": "",
"Default": "0.00",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "erloes_netto",
"Type": "decimal(19,2)",
"Collation": null,
"Null": "NO",
"Key": "",
"Default": "0.00",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "deckungsbeitrag",
"Type": "decimal(11,2)",
"Collation": null,
"Null": "NO",
"Key": "",
"Default": "0.00",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "provision_summe",
"Type": "decimal(11,2)",
"Collation": null,
"Null": "YES",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "vertriebid",
"Type": "int(11)",
"Collation": null,
"Null": "YES",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "gruppe",
"Type": "int(11)",
"Collation": null,
"Null": "NO",
"Key": "",
"Default": "0",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
{
"Field": "projekt",
"Type": "varchar(222)",
"Collation": "utf8mb3_general_ci",
"Null": "NO",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
}
],
"keys": []
},
},
{
"name": "belegevorlagen",
"type": "BASE TABLE",

View File

@ -7,6 +7,7 @@
*
*/
function echo_output(array $output) {
echo(implode("\n",$output)."\n");
}
@ -16,12 +17,6 @@ function abort(string $message) {
echo("--------------- Aborted! ---------------\n");
}
class DatabaseConnectionInfo {
function __construct() {
require_once('../conf/user.inc.php');
}
}
function git(string $command, &$output, bool $verbose, string $error_text) : int {
$output = array();
if ($verbose) {
@ -53,13 +48,14 @@ if (php_sapi_name() == "cli") {
if ($cli) {
if ($argc > 1) {
if (in_array('-c', $argv)) {
$check = true;
} else {
$check = false;
}
$check_git = false;
$do_git = false;
$check_db = false;
$do_db = false;
$do = false;
if ($argc > 1) {
if (in_array('-v', $argv)) {
$verbose = true;
@ -73,21 +69,37 @@ if ($cli) {
$force = false;
}
if (in_array('-do', $argv)) {
$check = true;
$do_upgrade = true;
if (in_array('-s', $argv)) {
$check_git = true;
} else {
$do_upgrade = false;
}
if (in_array('-db', $argv)) {
$check_db = true;
} else {
}
if (in_array('-do', $argv)) {
if (!$check_git && !$check_db) {
$do_git = true;
$do_db = true;
}
if ($check_git) {
$do_git = true;
}
if ($check_db) {
$do_db = true;
}
}
if (in_array('-utf8fix', $argv)) {
$utf8fix = true;
} else {
$utf8fix = false;
}
}
if ($check) {
upgrade_main($directory, $verbose, $do_upgrade, $force);
if ($check_git || $check_db || $do_git || $do_db) {
upgrade_main($directory,$verbose,$check_git,$do_git,$check_db,$do_db,$force);
} else {
info();
}
@ -99,16 +111,22 @@ if ($cli) {
}
// -------------------------------- END
function upgrade_main(string $directory,bool $verbose, bool $do_upgrade, bool $force) {
function upgrade_main(string $directory,bool $verbose, bool $check_git, bool $do_git, bool $check_db, bool $do_db, bool $force) {
$dbci = new DatabaseConnectionInfo;
class DatabaseConnectionInfo {
function __construct($dir) {
require($dir."/../conf/user.inc.php");
}
}
$dbci = new DatabaseConnectionInfo($directory);
$host = $dbci->WFdbhost;
$user = $dbci->WFdbuser;
$passwd = $dbci->WFdbpass;
$schema = $dbci->WFdbname;
require_once($directory.'/../tools/database_compare/mustal_mysql_upgrade_tool.php');
require_once($directory.'/../vendor/mustal/mustal_mysql_upgrade_tool.php');
$datafolder = $directory."/data";
$lockfile_name = $datafolder."/.in_progress.flag";
@ -126,109 +144,130 @@ function upgrade_main(string $directory,bool $verbose, bool $do_upgrade, bool $f
}
$remote_info = json_decode($remote_info_contents, true);
// Get changed files on system -> Should be empty
$output = array();
$retval = git("ls-files -m ..", $output,$verbose,"Git not initialized.");
$modified_files = false;
// Not a git repository -> Create it and then go ahead
if ($retval == 128) {
echo("Setting up git...");
$retval = git("init ..", $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
$retval = git("add ../.", $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
$retval = git("fetch ".$remote_info['host']." ".$remote_info['branch'], $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
$retval = git("checkout FETCH_HEAD -f", $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
}
if ($retval != 0) {
abort("Error while executing git!");
return(-1);
}
if ($verbose) {
echo("--------------- Upgrade history ---------------\n");
$retval = git("log --date=short-local --pretty=\"%cd (%h): %s\" HEAD --not HEAD~4",$output,$verbose,"Error while showing history!");
if ($retval != 0) {
abort("");
return(-1);
}
} else {
echo("--------------- Current version ---------------\n");
$retval = git("log -1 --date=short-local --pretty=\"%cd (%h): %s\" HEAD",$output,$verbose,"Error while showing history!");
if ($retval != 0) {
abort("");
return(-1);
}
}
if ($do_upgrade) {
if ($check_git || $do_git) {
// Get changed files on system -> Should be empty
$output = array();
$retval = git("ls-files -m ..", $output,$verbose,"Git not initialized.");
if (!empty($output)) {
echo("There are modified files:");
$modified_files = true;
echo("There are modified files:\n");
echo_output($output);
if (!$force) {
}
// Not a git repository -> Create it and then go ahead
if ($retval == 128) {
echo("Setting up git...");
$retval = git("init ..", $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
$retval = git("add ../.", $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
$retval = git("fetch ".$remote_info['host']." ".$remote_info['branch'], $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
$retval = git("checkout FETCH_HEAD -f", $output,$verbose,"Error while initializing git!");
if ($retval != 0) {
abort("");
return(-1);
}
} else if ($retval != 0) {
abort("Error while executing git!");
return(-1);
}
if ($verbose) {
echo("--------------- Upgrade history ---------------\n");
$retval = git("log --date=short-local --pretty=\"%cd (%h): %s\" HEAD --not HEAD~5",$output,$verbose,"Error while showing history!");
if ($retval != 0) {
abort("");
return(-1);
}
} else {
echo("--------------- Current version ---------------\n");
$retval = git("log -1 --date=short-local --pretty=\"%cd (%h): %s\" HEAD",$output,false,"Error while showing history!");
if ($retval != 0) {
return(-1);
}
echo_output($output);
}
if ($do_git) {
if ($modified_files && !$force) {
abort("Clear modified files or use -f");
return(-1);
}
}
echo("--------------- Pulling files... ---------------\n");
echo("--------------- Locking system ---------------\n");
if (file_exists($lockfile_name)) {
echo("System is already locked.\n");
} else {
file_put_contents($lockfile_name," ");
}
if ($force) {
$retval = git("reset --hard",$output,$verbose,"Error while resetting modified files!");
if ($retval != 0) {
echo_output($output);
abort("");
return(-1);
}
}
echo("--------------- Pulling files... ---------------\n");
$retval = git("pull ".$remote_info['host']." ".$remote_info['branch'],$output,$verbose,"Error while pulling files!");
if ($retval != 0) {
echo_output($output);
abort("");
return(-1);
}
if ($force) {
$retval = git("reset --hard",$output,$verbose,"Error while resetting modified files!");
$retval = git("reset --hard",$output,$verbose,"Error while applying files!");
if ($retval != 0) {
echo_output($output);
abort("");
return(-1);
}
}
$retval = git("pull ".$remote_info['host']." ".$remote_info['branch'],$output,$verbose,"Error while pulling files!");
if ($retval != 0) {
echo("--------------- Files upgrade completed ---------------\n");
$retval = git("log -1 ",$output,$verbose,"Error while checking files!");
if ($retval != 0) {
echo_output($output);
abort("");
return(-1);
}
echo_output($output);
abort("");
return(-1);
}
} // $do_git
else { // Dry run
echo("--------------- Dry run, use -do to upgrade ---------------\n");
echo("--------------- Fetching files... ---------------\n");
$retval = git("reset --hard",$output,$verbose,"Error while applying files!");
if ($retval != 0) {
echo_output($output);
abort("");
return(-1);
}
$retval = git("fetch ".$remote_info['host']." ".$remote_info['branch'],$output,$verbose,"Error while fetching files!");
if ($retval != 0) {
echo_output($output);
abort("");
}
echo("--------------- Files upgrade completed ---------------\n");
$retval = git("log -1 ",$output,$verbose,"Error while checking files!");
if ($retval != 0) {
echo_output($output);
abort("");
return(-1);
}
echo_output($output);
echo("--------------- Pending upgrades: ---------------\n");
$retval = git("log --date=short-local --pretty=\"%cd (%h): %s\" FETCH_HEAD --not HEAD",$output,$verbose,"Error while fetching files!");
if (!$verbose) {
echo_output($output);
}
if (empty($output)) {
echo("No upgrades pending.\n");
}
if ($retval != 0) {
abort("");
}
} // Dry run
} // $check_git
if ($check_db || $do_db) {
echo("--------------- Loading from database '$schema@$host'... ---------------\n");
$db_def = mustal_load_tables_from_db($host, $schema, $user, $passwd, $mustal_replacers);
@ -246,24 +285,25 @@ function upgrade_main(string $directory,bool $verbose, bool $do_upgrade, bool $f
return(-1);
}
echo("--------------- Comparing database '$schema@$host' vs. JSON '".$compare_def['database']."@".$compare_def['host']."' ---------------\n");
$compare_differences = mustal_compare_table_array($compare_def,"in JSON",$db_def,"in DB",true,true);
if($utf8fix) {
$column_collation_aliases = array(
['utf8mb3_general_ci','utf8_general_ci']
);
} else {
$column_collation_aliases = array();
if ($verbose) {
foreach ($compare_differences as $compare_difference) {
$comma = "";
foreach ($compare_difference as $key => $value) {
echo($comma."$key => [$value]");
$comma = ", ";
}
echo("\n");
}
}
$compare_differences = mustal_compare_table_array($compare_def,"in JSON",$db_def,"in DB",true,$column_collation_aliases);
echo((empty($compare_differences)?0:count($compare_differences))." differences.\n");
echo("--------------- Calculating database upgrade for '$schema@$host'... ---------------\n");
$upgrade_sql = array();
$result = mustal_calculate_db_upgrade($compare_def, $db_def, $upgrade_sql, $mustal_replacers);
if (!empty($result)) {
@ -276,80 +316,74 @@ function upgrade_main(string $directory,bool $verbose, bool $do_upgrade, bool $f
return(-1);
}
if ($verbose) {
foreach($upgrade_sql as $statement) {
echo($statement."\n");
}
}
echo(count($upgrade_sql)." upgrade statements\n");
echo("--------------- Executing database upgrade for '$schema@$host' database... ---------------\n");
// First get the contents of the database table structure
$mysqli = mysqli_connect($host, $user, $passwd, $schema);
/* Check if the connection succeeded */
if (!$mysqli) {
echo ("Failed to connect!\n");
} else {
if ($do_db) {
echo("--------------- Executing database upgrade for '$schema@$host' database... ---------------\n");
// First get the contents of the database table structure
$mysqli = mysqli_connect($host, $user, $passwd, $schema);
$counter = 0;
$error_counter = 0;
$number_of_statements = count($upgrade_sql);
/* Check if the connection succeeded */
if (!$mysqli) {
echo ("Failed to connect!\n");
} else {
foreach ($upgrade_sql as $sql) {
$counter = 0;
$error_counter = 0;
$number_of_statements = count($upgrade_sql);
$counter++;
echo("\rUpgrade step $counter of $number_of_statements... ");
foreach ($upgrade_sql as $sql) {
$counter++;
echo("\rUpgrade step $counter of $number_of_statements... ");
$query_result = mysqli_query($mysqli, $sql);
if (!$query_result) {
$error = " not ok: ". mysqli_error($mysqli);
echo($error);
echo("\n");
// file_put_contents("./errors.txt",date()." ".$error.$sql."\n",FILE_APPEND);
$error_counter++;
} else {
echo("ok.\r");
}
$query_result = mysqli_query($mysqli, $sql);
if (!$query_result) {
$error = " not ok: ". mysqli_error($mysqli);
echo($error);
echo("\n");
file_put_contents("./errors.txt",date()." ".$error.$sql."\n",FILE_APPEND);
$error_counter++;
} else {
echo("ok.\r");
}
echo("\n");
echo("$error_counter errors.\n");
if ($error_counter > 0) {
// echo("See 'errors.txt'\n");
}
echo("--------------- Checking database upgrade for '$schema@$host'... ---------------\n");
$db_def = mustal_load_tables_from_db($host, $schema, $user, $passwd, $mustal_replacers);
echo("--------------- Comparing database '$schema@$host' vs. JSON '".$compare_def['database']."@".$compare_def['host']."' ---------------\n");
$compare_differences = mustal_compare_table_array($compare_def,"in JSON",$db_def,"in DB",true,true);
echo((empty($compare_differences)?0:count($compare_differences))." differences.\n");
}
} // $do_db
} // $check_db
echo("\n");
echo("$error_counter errors.\n");
if ($error_counter > 0) {
echo("See 'errors.txt'\n");
}
echo("--------------- Checking database upgrade for '$schema@$host'... ---------------\n");
$db_def = mustal_load_tables_from_db($host, $schema, $user, $passwd, $mustal_replacers);
echo("--------------- Comparing database '$schema@$host' vs. JSON '".$compare_def['database']."@".$compare_def['host']."' ---------------\n");
$compare_differences = mustal_compare_table_array($compare_def,"in JSON",$db_def,"in DB",true,$column_collation_aliases);
echo((empty($compare_differences)?0:count($compare_differences))." differences.\n");
}
echo("--------------- Unlocking system ---------------\n");
unlink($lockfile_name);
}
else { // Dry run
echo("--------------- Dry run, use -do to upgrade ---------------\n");
echo("--------------- Fetching files... ---------------\n");
$retval = git("fetch ".$remote_info['host']." ".$remote_info['branch'],$output,$verbose,"Error while fetching files!");
if ($retval != 0) {
echo_output($output);
abort("");
}
echo("--------------- Pending upgrades: ---------------\n");
$retval = git("log --date=short-local --pretty=\"%cd (%h): %s\" FETCH_HEAD --not HEAD",$output,$verbose,"Error while fetching files!");
if (!$verbose) {
echo_output($output);
}
if (empty($output)) {
echo("No upgrades pending.\n");
}
if ($retval != 0) {
abort("");
}
/*
echo("--------------- Locking system ---------------\n");
if (file_exists($lockfile_name)) {
echo("System is already locked.\n");
} else {
file_put_contents($lockfile_name," ");
}
echo("--------------- Unlocking system ---------------\n");
unlink($lockfile_name);
*/
echo("--------------- Done! ---------------\n");
return(0);
}
@ -360,11 +394,12 @@ function info() {
echo("\n");
echo("Upgrade files and database\n");
echo("Options:\n");
echo("\t-c: check for upgrades\n");
echo("\t-s: check/do system upgrades\n");
echo("\t-db: check/do database upgrades\n");
echo("\t-do: execute all upgrades\n");
echo("\t-v: verbose output\n");
echo("\t-f: force override of existing files\n");
echo("\t-utf8fix: apply fix for 'utf8' != 'utf8mb3'\n");
echo("\t-do: execute the upgrade\n");
echo("\t-clean: (not yet implemented) create the needed SQL to remove items from the database not in the JSON\n");
echo("\n");
}

View File

@ -0,0 +1,674 @@
<?php
/*
MUSTAL Mysql Upgrade Schema Tool by Alex Ledis
Helper to compare database structures from JSON files vs. database and upgrade database
Copyright (c) 2022 Alex Ledis
Licensed under AGPL v3
Version 1.0
function mustal_load_tables_from_db(string $host, string $schema, string $user, string $passwd, $replacers) : array
Load structure from db connection to an array.
function mustal_save_tables_to_json(array $db_def, string $path, string $tables_file_name, bool $force) : int
Save structure from array to a JSON file.
function mustal_load_tables_from_json(string $path, string $tables_file_name) : array
Load structure from JSON file into array.
function mustal_compare_table_array(array $nominal, string $nominal_name, array $actual, string $actual_name, bool $check_column_definitions) : array
Compare two database structures
Returns a structured array containing information on all the differences.
function mustal_calculate_db_upgrade(array $compare_def, array $db_def, array &$upgrade_sql) : int
Generate the SQL needed to upgrade the database to match the definition, based on a comparison.
Data structure in Array and JSON
{
"host": "hostname",
"database": "schemaname",
"user": "username",
"tables": [
{
"name": "",
"type": "",
"columns": [
{
"Field": "",
"Type": "",
"Collation": "",
"Null": "",
"Key": "",
"Default": "",
"Extra": "",
"Privileges": "",
"Comment": ""
}
],
"keys": [
{
"Key_name": "",
"columns": [
"",
""
]
}
]
}
]
}
*/
// These default values will not be in quotes, converted to lowercase and be replaced by the second entry
$mustal_replacers = [
['current_timestamp','current_timestamp()'],
['on update current_timestamp','on update current_timestamp()']
];
// Load all db_def from a DB connection into a db_def array
function mustal_load_tables_from_db(string $host, string $schema, string $user, string $passwd, $replacers) : array {
// First get the contents of the database table structure
$mysqli = mysqli_connect($host, $user, $passwd, $schema);
/* Check if the connection succeeded */
if (!$mysqli) {
return(array());
}
// Get db_def and views
$sql = "SHOW FULL tables";
$query_result = mysqli_query($mysqli, $sql);
if (!$query_result) {
return(array());
}
while ($row = mysqli_fetch_assoc($query_result)) {
$table = array();
$table['name'] = $row['Tables_in_'.$schema];
$table['type'] = $row['Table_type'];
$tables[] = $table; // Add table to list of tables
}
// Get and add columns of the table
foreach ($tables as &$table) {
$sql = "SHOW FULL COLUMNS FROM ".$table['name'];
$query_result = mysqli_query($mysqli, $sql);
if (!$query_result) {
return(array());
}
$columns = array();
while ($column = mysqli_fetch_assoc($query_result)) {
// Do some harmonization
if ($column['Default'] !== NULL) {
mustal_sql_replace_reserved_functions($column,$replacers);
$column['Default'] = mustal_mysql_put_text_type_in_quotes($column['Type'],$column['Default']);
}
$columns[] = $column; // Add column to list of columns
}
$table['columns'] = $columns;
$sql = "SHOW KEYS FROM ".$table['name'];
$query_result = mysqli_query($mysqli, $sql);
if (!$query_result) {
return(array());
}
$keys = array();
while ($key = mysqli_fetch_assoc($query_result)) {
$keys[] = $key; // Add key to list of keys
}
// Compose comparable format for keys
$composed_keys = array();
foreach ($keys as $key) {
// Check if this key exists already
$key_pos = array_search($key['Key_name'],array_column($composed_keys,'Key_name'));
if ($key_pos == false) {
// New key
$composed_key = array();
$composed_key['Key_name'] = $key['Key_name'];
$composed_key['Index_type'] = $key['Index_type'];
$composed_key['columns'][] = $key['Column_name'];
$composed_keys[] = $composed_key;
} else {
// Given key, add column
$composed_keys[$key_pos]['columns'][] .= $key['Column_name'];
}
}
unset($key);
$table['keys'] = $composed_keys;
unset($composed_keys);
}
unset($table);
$result = array();
$result['host'] = $host;
$result['database'] = $schema;
$result['user'] = $user;
$result['tables'] = $tables;
return($result);
}
function mustal_save_tables_to_json(array $db_def, string $path, string $tables_file_name, bool $force) : int {
// Prepare db_def file
if (!is_dir($path)) {
mkdir($path);
}
if (!$force && file_exists($path."/".$tables_file_name)) {
return(2);
}
$tables_file = fopen($path."/".$tables_file_name, "w");
if (empty($tables_file)) {
return(2);
}
fwrite($tables_file, json_encode($db_def,JSON_PRETTY_PRINT));
fclose($tables_file);
return(0);
}
// Load all db_def from JSON file
function mustal_load_tables_from_json(string $path, string $tables_file_name) : array {
$db_def = array();
$contents = file_get_contents($path."/".$tables_file_name);
if (!$contents) {
return(array());
}
$db_def = json_decode($contents, true);
if (!$db_def) {
return(array());
}
return($db_def);
}
// Compare two definitions
// Report based on the first array
// Return Array
function mustal_compare_table_array(array $nominal, string $nominal_name, array $actual, string $actual_name, bool $check_column_definitions, bool $utf8fix) : array {
$compare_differences = array();
if($utf8fix) {
$column_collation_aliases = array(
['utf8mb3_general_ci','utf8_general_ci'],
['utf8mb3_unicode_ci','utf8_unicode_ci']
);
} else {
$column_collation_aliases = array();
}
if (count($nominal['tables']) != count($actual['tables'])) {
$compare_difference = array();
$compare_difference['type'] = "Table count";
$compare_difference[$nominal_name] = count($nominal['tables']);
$compare_difference[$actual_name] = count($actual['tables']);
$compare_differences[] = $compare_difference;
}
foreach ($nominal['tables'] as $database_table) {
$found_table = array();
foreach ($actual['tables'] as $compare_table) {
if ($database_table['name'] == $compare_table['name']) {
$found_table = $compare_table;
break;
}
}
unset($compare_table);
if ($found_table) {
// Check type table vs view
if ($database_table['type'] != $found_table['type']) {
$compare_difference = array();
$compare_difference['type'] = "Table type";
$compare_difference['table'] = $database_table['name'];
$compare_difference[$nominal_name] = $database_table['type'];
$compare_difference[$actual_name] = $found_table['type'];
$compare_differences[] = $compare_difference;
}
// Only BASE TABLE supported now
if ($found_table['type'] != 'BASE TABLE') {
continue;
}
// Check columns
$compare_table_columns = array_column($found_table['columns'],'Field');
foreach ($database_table['columns'] as $column) {
$column_name_to_find = $column['Field'];
$column_key = array_search($column_name_to_find,$compare_table_columns,true);
if ($column_key !== false) {
// Compare the properties of the columns
if ($check_column_definitions) {
$found_column = $found_table['columns'][$column_key];
foreach ($column as $key => $value) {
// Apply aliases
if (!empty($column_collation_aliases)) {
foreach($column_collation_aliases as $column_collation_alias) {
if ($value == $column_collation_alias[0]) {
$value = $column_collation_alias[1];
}
if ($found_column[$key] == $column_collation_alias[0]) {
$found_column[$key] = $column_collation_alias[1];
}
}
}
if ($found_column[$key] != $value) {
if ($key != 'Key') { // Keys will be handled separately
$compare_difference = array();
$compare_difference['type'] = "Column definition";
$compare_difference['table'] = $database_table['name'];
$compare_difference['column'] = $column['Field'];
$compare_difference['property'] = $key;
$compare_difference[$nominal_name] = $value;
$compare_difference[$actual_name] = $found_column[$key];
$compare_differences[] = $compare_difference;
}
}
}
unset($value);
} // $check_column_definitions
} else {
$compare_difference = array();
$compare_difference['type'] = "Column existence";
$compare_difference['table'] = $database_table['name'];
$compare_difference[$nominal_name] = $column['Field'];
$compare_differences[] = $compare_difference;
}
}
unset($column);
// Check keys
$compare_table_sql_indexs = array_column($found_table['keys'],'Key_name');
foreach ($database_table['keys'] as $sql_index) {
$sql_index_name_to_find = $sql_index['Key_name'];
$sql_index_key = array_search($sql_index_name_to_find,$compare_table_sql_indexs,true);
if ($sql_index_key !== false) {
// Compare the properties of the sql_indexs
if ($check_column_definitions) {
$found_sql_index = $found_table['keys'][$sql_index_key];
foreach ($sql_index as $key => $value) {
if ($found_sql_index[$key] != $value) {
// if ($key != 'permissions') {
$compare_difference = array();
$compare_difference['type'] = "Key definition";
$compare_difference['table'] = $database_table['name'];
$compare_difference['key'] = $sql_index['Key_name'];
$compare_difference['property'] = $key;
$compare_difference[$nominal_name] = implode(',',$value);
$compare_difference[$actual_name] = implode(',',$found_sql_index[$key]);
$compare_differences[] = $compare_difference;
// }
}
}
unset($value);
} // $check_sql_index_definitions
} else {
$compare_difference = array();
$compare_difference['type'] = "Key existence";
$compare_difference['table'] = $database_table['name'];
$compare_difference[$nominal_name] = $sql_index['Key_name'];
$compare_differences[] = $compare_difference;
}
}
unset($sql_index);
} else {
$compare_difference = array();
$compare_difference['type'] = "Table existence";
$compare_difference[$nominal_name] = $database_table['name'];
$compare_differences[] = $compare_difference;
}
}
unset($database_table);
return($compare_differences);
}
// Generate SQL to create or modify column
function mustal_column_sql_definition(string $table_name, array $column, array $reserved_words_without_quote) : string {
foreach($column as $key => &$value) {
$value = (string) $value;
$value = mustal_column_sql_create_property_definition($key,$value,$reserved_words_without_quote);
}
// Default handling here
if ($column['Default'] == " DEFAULT ''") {
$column['Default'] = "";
}
$sql =
$column['Type'].
$column['Null'].
$column['Default'].
$column['Extra'].
$column['Collation'];
return($sql);
}
// Generate SQL to modify a single column property
function mustal_column_sql_create_property_definition(string $property, string $property_value, array $reserved_words_without_quote) : string {
switch ($property) {
case 'Type':
break;
case 'Null':
if ($property_value == "NO") {
$property_value = " NOT NULL"; // Idiotic...
}
if ($property_value == "YES") {
$property_value = " NULL"; // Also Idiotic...
}
break;
case 'Default':
// Check for MYSQL function mustal_call as default
if (in_array(strtolower($property_value),$reserved_words_without_quote)) {
$quote = "";
} else {
// Remove quotes if there are
$property_value = trim($property_value,"'");
$quote = "'";
}
$property_value = " DEFAULT $quote".$property_value."$quote";
break;
case 'Extra':
if ($property_value != '') {
$property_value = " ".$property_value;
}
break;
case 'Collation':
if ($property_value != '') {
$property_value = " COLLATE ".$property_value;
}
break;
default:
$property_value = "";
break;
}
return($property_value);
}
// Replaces different variants of the same function mustal_to allow comparison
function mustal_sql_replace_reserved_functions(array &$column, array $replacers) {
$result = strtolower($column['Default']);
foreach ($replacers as $replace) {
if ($result == $replace[0]) {
$result = $replace[1];
}
}
$column['Default'] = $result;
$result = strtolower($column['Extra']);
foreach ($replacers as $replace) {
if ($result == $replace[0]) {
$result = $replace[1];
}
}
$column['Extra'] = $result;
}
// Is it a text type? -> Use quotes then
function mustal_mysql_put_text_type_in_quotes(string $checktype, string $value) : string {
$types = array('char','varchar','tinytext','text','mediumtext','longtext');
foreach($types as $type) {
if (stripos($checktype, $type) !== false) {
return("'".$value."'");
}
}
return($value);
}
function mustal_implode_with_quote(string $quote, string $delimiter, array $array_to_implode) : string {
return($quote.implode($quote.$delimiter.$quote, $array_to_implode).$quote);
}
// Calculate the sql neccessary to update the database
// returns array(code,text)
// Error codes:
// 0 ok
// 1 Upgrade type of table not supported
// 2 Error on table upgrade
// 3 Error on column existence upgrade
// 4 Error on column existence upgrade
// 5 Error on column definition upgrade
// 6 Error on column definition upgrade
// 7 Error on key existence upgrade
// 8 Error on key existence upgrade
// 9 Error on key definition upgrade
// 10 Error on key definition upgrade
// 11 Table type upgrade not supported
// 12 Upgrade type not supported
function mustal_calculate_db_upgrade(array $compare_def, array $db_def, array &$upgrade_sql, array $replacers) : array {
$result = array();
$upgrade_sql = array();
$compare_differences = mustal_compare_table_array($compare_def,"in JSON",$db_def,"in DB",true,true);
foreach ($compare_differences as $compare_difference) {
switch ($compare_difference['type']) {
case 'Table existence':
// Get table definition from JSON
$table_name = $compare_difference['in JSON'];
$table_key = array_search($table_name,array_column($compare_def['tables'],'name'));
if ($table_key !== false) {
$table = $compare_def['tables'][$table_key];
switch ($table['type']) {
case 'BASE TABLE':
// Create table in DB
$sql = "";
$sql = "CREATE TABLE `".$table['name']."` (";
$comma = "";
foreach ($table['columns'] as $column) {
$sql .= $comma."`".$column['Field']."` ".mustal_column_sql_definition($table_name, $column,array_column($replacers,1));
$comma = ", ";
}
// Add keys
$comma = ", ";
foreach ($table['keys'] as $key) {
if ($key['Key_name'] == 'PRIMARY') {
$keystring = "PRIMARY KEY ";
} else {
if(array_key_exists('Index_type', $key)) {
$index_type = $key['Index_type'];
} else {
$index_type = "";
}
$keystring = $index_type." KEY `".$key['Key_name']."` ";
}
$sql .= $comma.$keystring."(`".implode("`,`",$key['columns'])."`) ";
}
$sql .= ")";
$upgrade_sql[] = $sql;
break;
default:
$result[] = array(1,"Upgrade type '".$table['type']."' on table '".$table['name']."' not supported.");
break;
}
} else {
$result[] = array(2,"Error table_key while creating upgrade for table existence `$table_name`.");
}
break;
case 'Column existence':
$table_name = $compare_difference['table'];
$column_name = $compare_difference['in JSON'];
$table_key = array_search($table_name,array_column($compare_def['tables'],'name'));
if ($table_key !== false) {
$table = $compare_def['tables'][$table_key];
$columns = $table['columns'];
$column_key = array_search($column_name,array_column($columns,'Field'));
if ($column_key !== false) {
$column = $table['columns'][$column_key];
$sql = "ALTER TABLE `$table_name` ADD COLUMN `".$column_name."` ";
$sql .= mustal_column_sql_definition($table_name, $column, array_column($replacers,1));
$sql .= ";";
$upgrade_sql[] = $sql;
}
else {
$result[] = array(3,"Error column_key while creating column '$column_name' in table '".$table['name']."'.");
}
}
else {
$result[] = array(4,"Error table_key while creating upgrade for column existence '$column_name' in table '$table_name'.");
}
// Add Column in DB
break;
case 'Column definition':
$table_name = $compare_difference['table'];
$column_name = $compare_difference['column'];
$table_key = array_search($table_name,array_column($compare_def['tables'],'name'));
if ($table_key !== false) {
$table = $compare_def['tables'][$table_key];
$columns = $table['columns'];
$column_names = array_column($columns,'Field');
$column_key = array_search($column_name,$column_names);
if ($column_key !== false) {
$column = $table['columns'][$column_key];
$sql = "ALTER TABLE `$table_name` MODIFY COLUMN `".$column_name."` ";
$sql .= mustal_column_sql_definition($table_name, $column,array_column($replacers,1));
$sql .= ";";
$upgrade_sql[] = $sql;
}
else {
$result[] = array(5,"Error column_key while modifying column '$column_name' in table '".$table['name']."'.");
}
}
else {
$result[] = array(6,"Error table_key while modifying column '$column_name' in table '$table_name'.");
return(6);
}
// Modify Column in DB
break;
case 'Key existence':
$table_name = $compare_difference['table'];
$key_name = $compare_difference['in JSON'];
$table_key = array_search($table_name,array_column($compare_def['tables'],'name'));
if ($table_key !== false) {
$table = $compare_def['tables'][$table_key];
$keys = $table['keys'];
$key_names = array_column($keys,'Key_name');
$key_key = array_search($key_name,$key_names);
if ($key_key !== false) {
$key = $table['keys'][$key_key];
$sql = "ALTER TABLE `$table_name` ADD KEY `".$key_name."` ";
$sql .= "(`".implode("`,`",$key['columns'])."`)";
$sql .= ";";
$upgrade_sql[] = $sql;
}
else {
$result[] = array(7,"Error key_key while adding key '$key_name' in table '".$table['name']."'.");
}
}
else {
$result[] = array(8,"Error table_key while adding key '$key_name' in table '$table_name'.");
}
break;
case "Key definition":
$table_name = $compare_difference['table'];
$key_name = $compare_difference['key'];
$table_key = array_search($table_name,array_column($compare_def['tables'],'name'));
if ($table_key !== false) {
$table = $compare_def['tables'][$table_key];
$keys = $table['keys'];
$key_names = array_column($keys,'Key_name');
$key_key = array_search($key_name,$key_names);
if ($key_key !== false) {
$key = $table['keys'][$key_key];
$sql = "ALTER TABLE `$table_name` DROP KEY `".$key_name."`;";
$upgrade_sql[] = $sql;
$sql = "ALTER TABLE `$table_name` ADD KEY `".$key_name."` ";
$sql .= "(`".implode("`,`",$key['columns'])."`)";
$sql .= ";";
$upgrade_sql[] = $sql;
}
else {
$result[] = array(9, "Error key_key while changing key '$key_name' in table '".$table['name']."'.");
}
}
else {
$result[] = array(10,"Error table_key while changing key '$key_name' in table '$table_name'.");
}
break;
case 'Table count':
// Nothing to do
break;
case 'Table type':
$result[] = array(11,"Upgrade type '".$compare_difference['type']."' on table '".$compare_difference['table']."' not supported.");
break;
default:
$result[] = array(12,"Upgrade type '".$compare_difference['type']."' not supported.");
break;
}
}
$upgrade_sql = array_unique($upgrade_sql);
if (count($upgrade_sql) > 0) {
array_unshift($upgrade_sql,"SET SQL_MODE='ALLOW_INVALID_DATES';","SET SESSION innodb_strict_mode=OFF;");
}
return($result);
}

View File

@ -40,7 +40,7 @@ class upgrade {
$this->app->Tpl->Set('PROGRESS_VISIBLE', "hidden");
}
upgrade_main("../upgrade",$verbose,$do_upgrade,$force);
upgrade_main("../upgrade",$verbose,true,$do_upgrade,true,$do_upgrade,$force);
$result = ob_get_contents();
ob_end_clean();
$this->app->Tpl->Set('CURRENT', $this->app->erp->Revision());