yf_db_installer_mysql class| File | plugins/db/classes/db/yf_db_installer_mysql.class.php |
|---|---|
| Use | _class('db_installer_mysql', 'classes/db/') |
| Extends | yf_db_installer |
A site sets them in its config with $PROJECT_CONF['db_installer_mysql']['NAME'] = ...;
| Property | Default | Description |
|---|---|---|
$DEFAULT_CHARSETstring |
'utf8' |
|
$NO_REPAIR_TABLESarray |
[] |
|
$NUM_RETRIESint |
5 |
|
$RETRY_DELAYint |
0 |
|
$_DEF_TABLE_OPTIONS |
[] |
|
$_KNOWN_TABLE_OPTIONSarray |
|
from yf_db_installer: $LOCK_FILE_NAME, $LOCK_TIMEOUT, $OTHER_TABLES_DATAS, $OTHER_TABLES_STRUCTS, $RESTORE_FULLTEXT_INDEX, $SHARDING_BY_COUNTRY, $SHARDING_BY_DAY, $SHARDING_BY_LANG, $SHARDING_BY_MONTH, $SHARDING_BY_YEAR, $SYS_TABLES_DATAS, $SYS_TABLES_STRUCTS, $TABLES_DATA, $TABLES_SQL, $TABLES_SQL_PHP, $USE_CACHE, $USE_LOCKING, $USE_SQL_IF_NOT_EXISTS, $alter_table_post_callbacks, $alter_table_pre_callbacks, $create_table_post_callbacks, $create_table_pre_callbacks
public function db_query_safe($sql, $db)
Execute original query again safely.
public function db_query_safe($sql, $db)
{
if (isset($db->_repairs_by_sql[$sql]) && $db->_repairs_by_sql[$sql] >= $this->NUM_RETRIES) {
return false;
}
@$db->_repairs_by_sql[$sql]++;
$result = $db->query($sql);
if ( ! $result) {
if ($this->RETRY_DELAY) {
sleep($this->RETRY_DELAY);
}
$db_error = $db->_last_query_error ?? $db->error();
// repair() answers true for codes it does not handle, which would report this failed query as done
$repairable = (array) ($db->REPAIRABLE_MYSQL_ERRORS ?? []);
$result = ($db_error && in_array((int) ($db_error['code'] ?? 0), $repairable, true)) ? $this->repair($sql, $db_error, $db) : false;
}
return $result;
}
public function do_alter_table($full_table_name, $column_name, array $sql_php, $db)
$sql_php array public function do_alter_table($full_table_name, $column_name, array $sql_php, $db)
{
$column_data = $sql_php['fields'][$column_name];
$sql = 'ALTER TABLE ' . $full_table_name . ' ADD ' . _class('db_ddl_parser_mysql', 'classes/db/')->create_column_line($column_name, $column_data);
return $db->query($sql);
}
public function do_create_table($full_table_name, array $sql_php, $db)
$sql_php array public function do_create_table($full_table_name, array $sql_php, $db)
{
if ( ! empty($this->NO_REPAIR_TABLES) && in_array($full_table_name, $this->NO_REPAIR_TABLES)) {
return false;
}
$sql_php = $this->fix_sql_php($sql_php, $db);
foreach ((array) $this->_DEF_TABLE_OPTIONS as $k => $v) {
if ( ! isset($sql_php['options'][$k])) {
$sql_php['options'][$k] = $v;
}
}
$sql_php['name'] = $full_table_name;
$sql = _class('db_ddl_parser_mysql', 'classes/db/')->create($sql_php);
return $db->query($sql);
}
public function fix_sql_php(array $sql_php, $db)
$sql_php array public function fix_sql_php(array $sql_php, $db)
{
$innodb_has_fulltext = $this->innodb_has_fulltext($db);
if ( ! $innodb_has_fulltext) {
// Remove fulltext indexes from db structure before creating table
foreach ((array) $sql_php['indexes'] as $iname => $idx) {
if ($idx['type'] == 'fulltext') {
unset($sql_php['indexes'][$iname]);
}
}
}
return $sql_php;
}
public function innodb_has_fulltext($db)
public function innodb_has_fulltext($db)
{
if ( ! isset($db->_innodb_has_fulltext)) {
$db->_innodb_has_fulltext = (bool) version_compare($db->get_server_version(), '5.6.0', '>');
}
return $db->_innodb_has_fulltext;
}
public function repair($sql, $db_error, $db)
Trying to repair given table structure (and possibly data).
public function repair($sql, $db_error, $db)
{
$sql = trim($sql);
// #1191 Can't find FULLTEXT index matching the column list
if (in_array($db_error['code'], [1191]) && $this->RESTORE_FULLTEXT_INDEX) {
foreach ((array) conf('fulltext_needed_for') as $_fulltext_field) {
list($f_table, $f_field) = explode('.', $_fulltext_field);
if (empty($f_table) || false === strpos($sql, $f_table) || empty($f_field)) {
continue;
}
// Check if such index already exists
foreach ((array) $db->get_all('SHOW INDEX FROM ' . $f_table . '', 'Key_name') as $k => $v) {
if ($v['Column_name'] != $f_field) {
continue;
}
if (strtoupper($v['Index_type']) == 'FULLTEXT') {
continue 2;
}
}
// TODO: convert into db utils()
$db->query('ALTER TABLE ' . $f_table . ' ADD FULLTEXT KEY ' . $f_field . ' (' . $f_field . ')');
}
return $this->db_query_safe($sql, $db);
// Errors related to server high load (currently we will handle only SELECTs)
// #2013 means 'Lost connection to MySQL server during query'
// #1205 means 'Lock wait timeout expired. Transaction was rolled back' (InnoDB)
// #1213 means 'Transaction deadlock. You should rerun the transaction.' (InnoDB)
} elseif (in_array($db_error['code'], [2013, 1205, 1213]) && substr($sql, 0, strlen('SELECT ')) == 'SELECT ') {
return $this->db_query_safe($sql, $db);
// #1146 means "Table %s doesn't exist"
} elseif ($db_error['code'] == 1146) {
// Try to get table name from error message
preg_match('#Table [\'][a-z_0-9]+\.([a-z_0-9]+)[\'] doesn\'t exist#ims', $db_error['message'], $m);
$item_to_repair = trim($m[1]);
foreach (range(1, 3) as $n) {
$dot_pos = strpos($item_to_repair, '.');
if (false !== $dot_pos) {
$item_to_repair = substr($item_to_repair, $dot_pos);
}
}
if (substr($item_to_repair, 0, strlen($db->DB_PREFIX)) == $db->DB_PREFIX) {
$item_to_repair = substr($item_to_repair, strlen($db->DB_PREFIX));
}
if ( ! empty($item_to_repair)) {
if ( ! $this->create_table(str_replace('dbt_', '', $item_to_repair), $db)) {
return false;
}
}
return $this->db_query_safe($sql, $db);
// #1054 means "Unknown column %s"
} elseif ($db_error['code'] == 1054) {
// Try to get column name from error message
preg_match('#Unknown column [\']([a-z_0-9]+)[\'] in#ims', $db_error['message'], $m);
$item_to_repair = $m[1];
foreach (range(1, 3) as $n) {
$dot_pos = strpos((string) $item_to_repair, '.');
if (false !== $dot_pos) {
$item_to_repair = substr($item_to_repair, $dot_pos);
}
}
// Try to get table name from SQL
preg_match('#[\s]*(UPDATE|FROM|INTO)[\s]+[`]{0,1}([a-z_0-9]+)[`]{0,1}#ims', $sql, $m2);
$table_to_repair = $m2[2];
foreach (range(1, 3) as $n) {
$dot_pos = strpos($table_to_repair, '.');
if (false !== $dot_pos) {
$table_to_repair = substr($table_to_repair, $dot_pos);
}
}
if (substr($table_to_repair, 0, strlen($db->DB_PREFIX)) == $db->DB_PREFIX) {
$table_to_repair = substr($table_to_repair, strlen($db->DB_PREFIX));
}
if ( ! empty($item_to_repair) && ! empty($m2[2])) {
if ( ! $this->alter_table($table_to_repair, $item_to_repair, $db)) {
return false;
}
return $this->db_query_safe($sql, $db);
}
}
return true;
}
_ hooks and helpers; not routable as page actionspublic function _init()
Framework construct.
public function _init()
{
parent::_init();
$this->_DEF_TABLE_OPTIONS = [
'DEFAULT CHARSET' => $this->DEFAULT_CHARSET,
'ENGINE' => 'InnoDB',
];
}
from yf_db_installer: __call(), alter_table(), alter_table_post_hook(), alter_table_pre_hook(), create_table(), create_table_php_to_sql(), create_table_post_hook(), create_table_pre_hook(), create_table_sql_to_php(), db_table_struct_into_array(), get_all_struct_array(), get_shard_table_name(), get_table_struct_array_by_name(), import_data(), load_data(), seed_data(), seed_table_post()