$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) { $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] = $value; $compare_difference[$actual_name] = $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); foreach ($nominal['views'] as $database_view) { $found_view = array(); foreach ($actual['views'] as $compare_view) { if ($database_view['name'] == $compare_view['name']) { $found_view = $compare_view; break; } } unset($compare_view); if ($found_view) { if (trim($database_view['Create']) != trim($found_view['Create'])) { $compare_difference = array(); $compare_difference['type'] = "View definition"; $compare_difference[$nominal_name] = $database_view['name']; $compare_differences[] = $compare_difference; } } else { $compare_difference = array(); $compare_difference['type'] = "View existence"; $compare_difference[$nominal_name] = $database_view['name']; $compare_differences[] = $compare_difference; } } 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 { $column_is_string_type = mustal_is_string_type($column['Type']); foreach($column as $key => &$value) { $value = (string) $value; $value = mustal_column_sql_create_property_definition($key,$value,$reserved_words_without_quote,$column_is_string_type); } // 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, $column_is_string_type) : 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 != '' && $column_is_string_type) { $property_value = " COLLATE ".$property_value; } else { $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 = $column['Default']; foreach ($replacers as $replace) { if (strtolower($column['Default']) == $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, bool $strict, bool $drop_keys) : array { $result = array(); $upgrade_sql = array(); if ($drop_keys) { foreach ($db_def['tables'] as $table_id => $table) { foreach ($table['keys'] as $key_id => $key) { if ($key['Key_name'] != 'PRIMARY') { $upgrade_sql[] = "ALTER TABLE `".$table['name']. "` DROP KEY `".$key['Key_name']."`;"; unset($db_def['tables'][$table_id]['keys'][$key_id]); } } } } $compare_differences = mustal_compare_table_array($compare_def,"in JSON",$db_def,"in DB",true,true); foreach ($compare_differences as $compare_difference) { $drop_view = false; 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 { $keystring = mustal_key_type(" ".$key['Non_unique']." KEY `".$key['Key_name']."` ",$key['Index_type']); } $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 ".mustal_key_type(" ".$key['Non_unique']." KEY `".$key['Key_name']."` "."(`".implode("`,`",$key['columns'])."`)",$key['Index_type']).";"; $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 ".mustal_key_type(" ".$key['Non_unique']." KEY `".$key['Key_name']."` ",$key['Index_type']); $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; case 'View definition': $drop_view = true; // intentionally omitted break; case 'View existence': $view_name = $compare_difference['in JSON']; $view_key = array_search($view_name,array_column($compare_def['views'],'name')); if ($view_key !== false) { $view = $compare_def['views'][$view_key]; switch ($view['type']) { case 'VIEW': if ($drop_view === true) { $sql = "DROP VIEW ".$view['name']; $upgrade_sql[] = $sql; } // Create view in DB $upgrade_sql[] = $view['Create']; break; default: $result[] = array(1,"Upgrade type '".$view['type']."' on view '".$view['name']."' not supported."); break; } } else { $result[] = array(2,"Error view_key while creating upgrade for view existence `$view_name`."); } 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';"); if (!$strict) { array_unshift($upgrade_sql,"SET SESSION innodb_strict_mode=OFF;"); } } return($result); } // Check if given type is a string, relevant for collation function mustal_is_string_type(string $type) { $mustal_string_types = array('varchar','char','text','tinytext','mediumtext','longtext'); foreach($mustal_string_types as $string_type) { if (stripos($type,$string_type) === 0) { return(true); } } return(false); } // create correct index type syntax function mustal_key_type(string $key_definition_string, string $key_type) { // Key types with using syntax $mustal_key_types_using_mapping = [ 'BTREE', 'HASH' ]; if (in_array($key_type,$mustal_key_types_using_mapping)) { return ($key_definition_string." USING ".$key_type); } else { return ($key_type." ".$key_definition_string); } }