function bb_sql_parse($sql) { require_once BACKPRESS_PATH . 'class.bp-sql-schema-parser.php'; bb_log_deprecated('function', __FUNCTION__, 'BP_SQL_Schema_Parser::parse'); return BP_SQL_Schema_Parser::parse($sql); }
/** * Evaluates the difference between a given set of SQL queries and real database structure */ function delta($db_object, $queries, $ignore = false, $execute = true) { if (!$db_object || !is_object($db_object) || !(is_a($db_object, 'BPDB') || is_a($db_object, 'BPDB_Multi') || is_a($db_object, 'BPDB_Hyper'))) { return __('Passed variable is not a BackPress database object.'); } if (!($_queries = BP_SQL_Schema_Parser::parse($queries))) { return __('No schema available.'); } // Set up default elements to ignore $ignore_defaults = array('tables' => array(), 'columns' => array(), 'indices' => array()); // Add the elements to ignore that were passed to the function if (!$ignore || !is_array($ignore)) { $ignore = $ignore_defaults; } else { if (isset($ignore['tables']) && is_array($ignore['tables'])) { $ignore['tables'] = array_merge($ignore_defaults['tables'], $ignore['tables']); } if (isset($ignore['columns']) && is_array($ignore['columns'])) { $ignore['columns'] = array_merge($ignore_defaults['columns'], $ignore['columns']); } if (isset($ignore['indices']) && is_array($ignore['indices'])) { $ignore['indices'] = array_merge($ignore_defaults['indices'], $ignore['indices']); } } // Build an array of $db_object registered tables and their database identifiers $_tables = $db_object->tables; $db_object_tables = array(); foreach ($_tables as $_table_id => $_table_name) { if (is_array($_table_name) && isset($db_object->db_servers['dbh_' . $_table_name[0]])) { $db_object_tables[$db_object->{$_table_id}] = 'dbh_' . $_table_name[0]; } else { $db_object_tables[$db_object->{$_table_id}] = 'dbh_global'; } } unset($_tables, $_table_id, $_table_name); $alterations = array(); // Loop through table queries if (isset($_queries['tables'])) { foreach ($_queries['tables'] as $_new_table_name => $_new_table_data) { if (in_array($_new_table_name, $ignore['tables'])) { continue; } // See if the table is custom and registered in $db_object under a custom database if (isset($db_object_tables[$_new_table_name]) && $db_object_tables[$_new_table_name] != 'dbh_global' && isset($db_object->db_servers[$db_object_tables[$_new_table_name]]['ds'])) { // Force the database connection $_dbhname = $db_object->db_servers[$db_object_tables[$_new_table_name]]['ds']; $db_object->_force_dbhname = $_dbhname; } else { $_dbhname = 'dbh_global'; } // Fetch the existing table column structure from the database $db_object->suppress_errors(); if (!($_existing_table_columns = $db_object->get_results('DESCRIBE `' . $_new_table_name . '`;', ARRAY_A))) { $db_object->suppress_errors(false); // The table doesn't exist, add it and then continue to the next table $alterations[$_dbhname][$_new_table_name][] = array('action' => 'create_table', 'message' => __('Creating table'), 'query' => $_new_table_data['query_tidy']); continue; } $db_object->suppress_errors(false); // Add an index to the existing columns array $__existing_table_columns = array(); foreach ($_existing_table_columns as $_existing_table_column) { // Remove 'Key' from returned column structure unset($_existing_table_column['Key']); $__existing_table_columns[$_existing_table_column['Field']] = $_existing_table_column; } $_existing_table_columns = $__existing_table_columns; unset($__existing_table_columns); // Loop over the columns in this table and look for differences foreach ($_new_table_data['columns'] as $_new_column_name => $_new_column_data) { if (isset($ignore['columns'][$_new_table_name]) && in_array($_new_column_name, $ignore['columns'][$_new_table_name])) { continue; } if (!in_array($_new_column_data, $_existing_table_columns)) { // There is a difference if (!isset($_existing_table_columns[$_new_column_name])) { // The column doesn't exist, so add it $alterations[$_dbhname][$_new_table_name][] = array('action' => 'add_column', 'message' => sprintf(__('Adding column: %s'), $_new_column_name), 'column' => $_new_column_name, 'query' => 'ALTER TABLE `' . $_new_table_name . '` ADD COLUMN ' . BP_SQL_Schema_Parser::get_column_definition($_new_column_data) . ';'); continue; } // Adjust defaults on columns that allow defaults if ($_new_column_data['Default'] !== $_existing_table_columns[$_new_column_name]['Default'] && !in_array(strtolower($_new_column_data['Type']), array('tinytext', 'text', 'mediumtext', 'longtext', 'blob', 'mediumblob', 'longblob'))) { // Change the default value for the column $alterations[$_dbhname][$_new_table_name][] = array('action' => 'set_default', 'message' => sprintf(__('Setting default on column: %s'), $_new_column_name), 'column' => $_new_column_name, 'query' => 'ALTER TABLE `' . $_new_table_name . '` ALTER COLUMN `' . $_new_column_name . '` SET DEFAULT \'' . $_new_column_data['Default'] . '\';'); // Don't continue, overwrite this if the next conditional is met } if ($_new_column_data['Type'] !== $_existing_table_columns[$_new_column_name]['Type'] || ('YES' === $_new_column_data['Null'] xor 'YES' === $_existing_table_columns[$_new_column_name]['Null']) || $_new_column_data['Extra'] !== $_existing_table_columns[$_new_column_name]['Extra']) { // Change the structure for the column $alterations[$_dbhname][$_new_table_name][] = array('action' => 'change_column', 'message' => sprintf(__('Changing column: %s'), $_new_column_name), 'column' => $_new_column_name, 'query' => 'ALTER TABLE `' . $_new_table_name . '` CHANGE COLUMN `' . $_new_column_name . '` ' . BP_SQL_Schema_Parser::get_column_definition($_new_column_data) . ';'); } } } unset($_existing_table_columns, $_new_column_name, $_new_column_data); // Fetch the table index structure from the database if (!($_existing_table_indices = $db_object->get_results('SHOW INDEX FROM `' . $_new_table_name . '`;', ARRAY_A))) { continue; } // Add an index to the existing columns array and organise by index name $__existing_table_indices = array(); foreach ($_existing_table_indices as $_existing_table_index) { // Remove unused parts from returned index structure unset($_existing_table_index['Collation'], $_existing_table_index['Cardinality'], $_existing_table_index['Packed'], $_existing_table_index['Null'], $_existing_table_index['Comment']); $__existing_table_indices[$_existing_table_index['Key_name']][] = $_existing_table_index; } $_existing_table_indices = $__existing_table_indices; unset($__existing_table_indices); // Loop over the indices in this table and look for differences foreach ($_new_table_data['indices'] as $_new_index_name => $_new_index_data) { if (isset($ignore['indices'][$_new_table_name]) && in_array($_new_index_name, $ignore['indices'][$_new_table_name])) { continue; } if (!in_array($_new_index_data, $_existing_table_indices)) { // There is a difference if (!isset($_existing_table_indices[$_new_index_name])) { // The index doesn't exist, so add it $alterations[$_dbhname][$_new_table_name][] = array('action' => 'add_index', 'message' => sprintf(__('Adding index: %s'), $_new_index_name), 'index' => $_new_index_name, 'query' => 'ALTER TABLE `' . $_new_table_name . '` ADD ' . BP_SQL_Schema_Parser::get_index_definition($_new_index_data) . ';'); continue; } if ($_new_index_data !== $_existing_table_indices[$_new_index_name]) { // The index is incorrect, so drop it and add the new one if ($_new_index_name == 'PRIMARY') { $_drop_index_name = 'PRIMARY KEY'; } else { $_drop_index_name = 'INDEX `' . $_new_index_name . '`'; } $alterations[$_dbhname][$_new_table_name][] = array('action' => 'drop_index', 'message' => sprintf(__('Dropping index: %s'), $_new_index_name), 'index' => $_new_index_name, 'query' => 'ALTER TABLE `' . $_new_table_name . '` DROP ' . $_drop_index_name . ';'); unset($_drop_index_name); $alterations[$_dbhname][$_new_table_name][] = array('action' => 'add_index', 'message' => sprintf(__('Adding index: %s'), $_new_index_name), 'index' => $_new_index_name, 'query' => 'ALTER TABLE `' . $_new_table_name . '` ADD ' . BP_SQL_Schema_Parser::get_index_definition($_new_index_data) . ';'); } } } unset($_new_index_name, $_new_index_data); // Go back to the default database connection $db_object->_force_dbhname = false; } unset($_new_table_name, $_new_table_data, $_dbhname); } // Now deal with the sundry INSERT and UPDATE statements (if any) if (isset($_queries['insert']) && is_array($_queries['insert']) && count($_queries['insert'])) { foreach ($_queries['insert'] as $_table_name => $_inserts) { foreach ($_inserts as $_insert) { $alterations['dbh_global'][$_table_name][] = array('action' => 'insert', 'message' => __('Inserting data'), 'query' => $_insert); } unset($_insert); } unset($_table_name, $_inserts); } if (isset($_queries['update']) && is_array($_queries['update']) && count($_queries['update'])) { foreach ($_queries['update'] as $_table_name => $_updates) { foreach ($_updates as $_update) { $alterations['dbh_global'][$_table_name][] = array('action' => 'update', 'message' => __('Updating data'), 'query' => $_update); } unset($_update); } unset($_table_name, $_updates); } // Initialise an array to hold the output messages $messages = array(); $errors = array(); foreach ($alterations as $_dbhname => $_tables) { // Force the database connection (this was already checked to be valid in the previous loop) $db_object->_force_dbhname = $_dbhname; // Note the database in the return messages $messages[] = '>>> ' . sprintf(__('Modifying database: %s (%s)'), $db_object->db_servers[$_dbhname]['name'], $db_object->db_servers[$_dbhname]['host']); foreach ($_tables as $_table_name => $_alterations) { // Note the table in the return messages $messages[] = '>>>>>> ' . sprintf(__('Table: %s'), $_table_name); foreach ($_alterations as $_alteration) { // If there is no query, then skip if (!$_alteration['query']) { continue; } // Note the action in the return messages $messages[] = '>>>>>>>>> ' . $_alteration['message']; if (!$execute) { $messages[] = '>>>>>>>>>>>> ' . __('Skipped'); continue; } // Run the query $_result = $db_object->query($_alteration['query']); $_result_error = $db_object->get_error(); if ($_result_error) { // There was an error $_result =& $_result_error; unset($_result_error); $messages[] = '>>>>>>>>>>>> ' . __('SQL ERROR! See the error log for more detail'); $errors[] = __('SQL ERROR!'); $errors[] = '>>> ' . sprintf(__('Database: %s (%s)'), $db_object->db_servers[$_dbhname]['name'], $db_object->db_servers[$_dbhname]['host']); $errors[] = '>>>>>> ' . $_result->error_data['db_query']['query']; $errors[] = '>>>>>> ' . $_result->error_data['db_query']['error']; } else { $messages[] = '>>>>>>>>>>>> ' . __('Done'); } unset($_result); } unset($_alteration); } unset($_table_name, $_alterations); } unset($_dbhname, $_tables); // Reset the database connection $db_object->_force_dbhname = false; return array('messages' => $messages, 'errors' => $errors); }