Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Schema checker] (Database FIX) Add support for checking NULL and DEFAULT column attributes #17351

Merged
merged 4 commits into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion administrator/language/en-GB/en-GB.com_installer.ini
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ COM_INSTALLER_MINIMUM_STABILITY_RC="Release Candidate"
COM_INSTALLER_MSG_DATABASE="This screen allows to you check that your database table structure is up to date with changes from the previous versions."
COM_INSTALLER_MSG_DATABASE_ADD_COLUMN="Table %2$s does not have column %3$s. (From file %1$s.)"
COM_INSTALLER_MSG_DATABASE_ADD_INDEX="Table %2$s does not have index %3$s. (From file %1$s.)"
COM_INSTALLER_MSG_DATABASE_CHANGE_COLUMN_TYPE="Table %2$s does not have column %3$s with type %4$s. (From file %1$s.)"
COM_INSTALLER_MSG_DATABASE_CHANGE_COLUMN_TYPE="Table %2$s has the wrong type or attributes for column %3$s with type %4$s. (From file %1$s.)"
COM_INSTALLER_MSG_DATABASE_CHECKED_OK="%s database changes were checked."
COM_INSTALLER_MSG_DATABASE_CREATE_TABLE="Table %2$s does not exist. (From file %1$s.)"
COM_INSTALLER_MSG_DATABASE_DRIVER="Database driver: %s."
Expand Down
88 changes: 85 additions & 3 deletions libraries/src/Schema/ChangeItem/MysqlChangeItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected function buildCheckQuery()
$find = array('#((\s*)\(\s*([^)\s]+)\s*)(\))#', '#(\s)(\s*)#');
$replace = array('($3)', '$1');
$updateQuery = preg_replace($find, $replace, $this->updateQuery);
$wordArray = explode(' ', $updateQuery);
$wordArray = preg_split("~'[^']*'(*SKIP)(*F)|\s+~u", trim($updateQuery, "; \t\n\r\0\x0B"));

// First, make sure we have an array of at least 6 elements
// if not, we can't make a check query for this one
Expand Down Expand Up @@ -153,14 +153,21 @@ protected function buildCheckQuery()
$type = $this->fixInteger($wordArray[5], $wordArray[6]);
}

// Detect changes in NULL and in DEFAULT column attributes
$changesArray = array_slice($wordArray, 6);
$defaultCheck = $this->checkDefault($changesArray, $type);
$nullCheck = $this->checkNull($changesArray);

/**
* When we made the UTF8MB4 conversion then text becomes medium text - so loosen the checks to these two types
* otherwise (for example) the profile fields profile_value check fails - see https://github.com/joomla/joomla-cms/issues/9258
*/
$typeCheck = $this->fixUtf8mb4TypeChecks($type);

$result = 'SHOW COLUMNS IN ' . $wordArray[2] . ' WHERE field = ' . $this->fixQuote($wordArray[4])
. ' AND ' . $typeCheck;
. ' AND ' . $typeCheck
. ($defaultCheck ? ' AND ' . $defaultCheck : '')
. ($nullCheck ? ' AND ' . $nullCheck : '');
$this->queryType = 'CHANGE_COLUMN_TYPE';
$this->msgElements = array($this->fixQuote($wordArray[2]), $this->fixQuote($wordArray[4]), $type);
}
Expand All @@ -173,6 +180,11 @@ protected function buildCheckQuery()
{
$type = $this->fixInteger($wordArray[6], $wordArray[7]);
}

// Detect changes in NULL and in DEFAULT column attributes
$changesArray = array_slice($wordArray, 6);
$defaultCheck = $this->checkDefault($changesArray, $type);
$nullCheck = $this->checkNull($changesArray);

/**
* When we made the UTF8MB4 conversion then text becomes medium text - so loosen the checks to these two types
Expand All @@ -181,7 +193,9 @@ protected function buildCheckQuery()
$typeCheck = $this->fixUtf8mb4TypeChecks($type);

$result = 'SHOW COLUMNS IN ' . $wordArray[2] . ' WHERE field = ' . $this->fixQuote($wordArray[5])
. ' AND ' . $typeCheck;
. ' AND ' . $typeCheck
. ($defaultCheck ? ' AND ' . $defaultCheck : '')
. ($nullCheck ? ' AND ' . $nullCheck : '');
$this->queryType = 'CHANGE_COLUMN_TYPE';
$this->msgElements = array($this->fixQuote($wordArray[2]), $this->fixQuote($wordArray[5]), $type);
}
Expand Down Expand Up @@ -307,4 +321,72 @@ private function fixUtf8mb4TypeChecks($type)

return $typeCheck;
}

/**
* Create query clause for column changes/modifications for NULL attribute
*
* @param array $changesArray The array of words after COLUMN name
*
* @return string The query clause for NULL check in the check query
*
* @since __DEPLOY_VERSION__
*/
private function checkNull($changesArray)
{
// Find NULL keyword
$index = array_search('null', array_map('strtolower', $changesArray));

// Create the check
if ($index !== false)
{
if ($index == 0 || strtolower($changesArray[$index - 1]) !== 'not')
{
return ' `null` = ' . $this->db->quote('YES');
}
else
{
return ' `null` = ' . $this->db->quote('NO');
}
}

return false;
}

/**
* Create query clause for column changes/modifications for DEFAULT attribute
*
* @param array $changesArray The array of words after COLUMN name
* @param string $type The type of the COLUMN
*
* @return string The query clause for DEFAULT check in the check query
*
* @since __DEPLOY_VERSION__
*/
private function checkDefault($changesArray, $type)
{
// Skip types that do not support default values
$type = strtolower($type);
if (substr($type, -4) === 'text' || substr($type, -4) === 'blob')
{
return false;
}

// Find DEFAULT keyword
$index = array_search('default', array_map('strtolower', $changesArray));

// Create the check
if ($index !== false)
{
if (strtolower($changesArray[$index + 1]) === 'null')
{
return ' `default` IS NULL';
}
else
{
return ' `default` = ' . $changesArray[$index + 1];
}
}

return false;
}
}