From f9b9aa4b8ec53fe59e23ef447164012f4f81db16 Mon Sep 17 00:00:00 2001 From: Chris Burgess Date: Mon, 13 Jun 2016 16:32:54 +1200 Subject: [PATCH] CRM-18811. Permit spaces in table and column aliases. Spaces are permitted provided the aliases are surrounded by backticks. This is not intended to be a complete representation of what MySQL permits, it's just expanding to permit things that CiviCRM actually generates. --- CRM/Utils/Rule.php | 13 +++++++++---- tests/phpunit/CRM/Utils/TypeTest.php | 13 +++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CRM/Utils/Rule.php b/CRM/Utils/Rule.php index 0ea7c32e3cc3..a1d8a9a10318 100644 --- a/CRM/Utils/Rule.php +++ b/CRM/Utils/Rule.php @@ -100,10 +100,15 @@ public static function mysqlColumnNameOrAlias($str) { return FALSE; } - // Ensure the string contains only valid characters: - // For column names: alphanumeric and underscores - // For aliases: backticks, alphanumeric hyphens and underscores. - if (!preg_match('/^((`[\w-]{1,64}`|[\w-]{1,64})\.)?(`[\w-]{1,64}`|[\w-]{1,64})$/i', $str)) { + // Ensure $str conforms to expected format. Not a complete expression of + // what MySQL permits; this should permit the formats CiviCRM generates. + // + // * Table name prefix is optional. + // * Table & column names & aliases: + // * Composed of alphanumeric chars, underscore and hyphens. + // * Maximum length of 64 chars. + // * Optionally surrounded by backticks, in which case spaces also OK. + if (!preg_match('/^((`[\w- ]{1,64}`|[\w-]{1,64})\.)?(`[\w- ]{1,64}`|[\w-]{1,64})$/i', $str)) { return FALSE; } diff --git a/tests/phpunit/CRM/Utils/TypeTest.php b/tests/phpunit/CRM/Utils/TypeTest.php index 3b6a853cecb5..e929343668a9 100644 --- a/tests/phpunit/CRM/Utils/TypeTest.php +++ b/tests/phpunit/CRM/Utils/TypeTest.php @@ -2,6 +2,8 @@ /** * Class CRM_Utils_TypeTest + * @package CiviCRM + * @subpackage CRM_Utils_Type * @group headless */ class CRM_Utils_TypeTest extends CiviUnitTestCase { @@ -46,12 +48,23 @@ public function validateDataProvider() { array('table.`Home-street_address`', 'MysqlColumnNameOrAlias', 'table.`Home-street_address`'), array('`table-alias`.`Home-street_address`', 'MysqlColumnNameOrAlias', '`table-alias`.`Home-street_address`'), array('`table-alias`.column', 'MysqlColumnNameOrAlias', '`table-alias`.column'), + // Spaces also permitted, only when enclosed in backticks. + array('`column alias`', 'MysqlColumnNameOrAlias', '`column alias`'), + array('`table alias`.column', 'MysqlColumnNameOrAlias', '`table alias`.column'), + array('`table alias`.`column alias`', 'MysqlColumnNameOrAlias', '`table alias`.`column alias`'), + array('table alias.column alias', 'MysqlColumnNameOrAlias', NULL), + array('table alias.column_alias', 'MysqlColumnNameOrAlias', NULL), + array('table_alias.column alias', 'MysqlColumnNameOrAlias', NULL), + // Functions are not permitted. array('column_name, sleep(5)', 'MysqlColumnNameOrAlias', NULL), + // Length checking permits only 64 chars. array(str_repeat('a', 64), 'MysqlColumnNameOrAlias', str_repeat('a', 64)), array(str_repeat('a', 65), 'MysqlColumnNameOrAlias', NULL), array(str_repeat('a', 64) . '.' . str_repeat('a', 64), 'MysqlColumnNameOrAlias', str_repeat('a', 64) . '.' . str_repeat('a', 64)), + array('`' . str_repeat('a', 64) . '`.`' . str_repeat('b', 64) . '`', 'MysqlColumnNameOrAlias', '`' . str_repeat('a', 64) . '`.`' . str_repeat('b', 64) . '`'), array(str_repeat('a', 64) . '.' . str_repeat('a', 65), 'MysqlColumnNameOrAlias', NULL), array(str_repeat('a', 65) . '.' . str_repeat('a', 64), 'MysqlColumnNameOrAlias', NULL), + // ORDER BY can be ASC or DESC, case not significant. array('asc', 'MysqlOrderByDirection', 'asc'), array('DESC', 'MysqlOrderByDirection', 'desc'), array('DESCc', 'MysqlOrderByDirection', NULL),