From 77d0cfd68efecc834fcbc4746da17facfae333ad Mon Sep 17 00:00:00 2001 From: pupi1985 Date: Sat, 17 Aug 2024 01:20:30 -0300 Subject: [PATCH 1/2] Ability to define connection and table creation charset and collation --- qa-config-example.php | 10 ++++++++- qa-include/db/install.php | 2 +- qa-include/qa-base.php | 7 ++++++ qa-include/qa-db.php | 26 +++++++++++++++++++++- qa-plugin/event-logger/qa-event-logger.php | 2 +- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/qa-config-example.php b/qa-config-example.php index 7f555c658..f0e19f437 100644 --- a/qa-config-example.php +++ b/qa-config-example.php @@ -49,9 +49,17 @@ 5. Place all the Question2Answer files on your server. 6. Open the appropriate URL, and follow the instructions. - More detailed installation instructions here: http://www.question2answer.org/ + More detailed installation instructions here: https://www.question2answer.org */ + +/* + The QA_MYSQL_CHARSET and QA_MYSQL_COLLATION define the charset and collation used by Q2A to + connect to the server, and to create tables and fields. +*/ + + define('QA_MYSQL_CHARSET', 'utf8mb4'); + define('QA_MYSQL_COLLATION', 'utf8mb4_unicode_ci'); /* ====================================================================== OPTIONAL CONSTANT DEFINITIONS, INCLUDING SUPPORT FOR SINGLE SIGN-ON diff --git a/qa-include/db/install.php b/qa-include/db/install.php index f7bd7d81b..301996ce7 100644 --- a/qa-include/db/install.php +++ b/qa-include/db/install.php @@ -714,7 +714,7 @@ function qa_db_create_table_sql($rawname, $definition) if (isset($coldef)) $querycols .= (strlen($querycols) ? ', ' : '') . (is_int($colname) ? $coldef : ($colname . ' ' . $coldef)); - return 'CREATE TABLE ^' . $rawname . ' (' . $querycols . ') ENGINE=InnoDB CHARSET=utf8'; + return 'CREATE TABLE ^' . $rawname . ' (' . $querycols . ') ENGINE=InnoDB ' . qa_get_table_charset_collation(); } diff --git a/qa-include/qa-base.php b/qa-include/qa-base.php index c972a1e51..0eb3adb0b 100644 --- a/qa-include/qa-base.php +++ b/qa-include/qa-base.php @@ -313,6 +313,13 @@ function qa_undo_wordpress_quoting($param, $isget) define('QA_FINAL_MYSQL_PORT', QA_MYSQL_PORT); } + if (!defined('QA_MYSQL_CHARSET')) { + define('QA_MYSQL_CHARSET', 'utf8'); // Use hardcoded default until v1.8.8 + } + if (!defined('QA_MYSQL_COLLATION')) { + define('QA_MYSQL_COLLATION', null); // Use hardcoded default until v1.8.8 + } + // Possible URL schemes for Q2A and the string used for url scheme testing define('QA_URL_FORMAT_INDEX', 0); // http://...../index.php/123/why-is-the-sky-blue diff --git a/qa-include/qa-db.php b/qa-include/qa-db.php index 2d8759f31..e236ff702 100644 --- a/qa-include/qa-db.php +++ b/qa-include/qa-db.php @@ -94,8 +94,15 @@ function qa_db_connect($failhandler = null) // From Q2A 1.5, we explicitly set the character encoding of the MySQL connection, instead of using lots of "SELECT BINARY col"-style queries. // Testing showed that overhead is minimal, so this seems worth trading off against the benefit of more straightforward queries, especially // for plugin developers. - if (!$db->set_charset('utf8')) + if ($db->set_charset(QA_MYSQL_CHARSET)) { + $sql = 'SET NAMES ' . QA_MYSQL_CHARSET; + if (QA_MYSQL_COLLATION !== null) { + $sql .= ' COLLATE ' . QA_MYSQL_COLLATION; + } + $db->query($sql); + } else { qa_db_fail_error('set_charset', $db->errno, $db->error); + } qa_report_process_stage('db_connected'); @@ -174,6 +181,23 @@ function qa_db_disconnect() } } +/** + * Return the default charset and collation string to use in CREATE TABLE statements. For fields that + * have not been set an implicit charset or collation, these values will be assigned at creation time. + * Collation might be null to provide backwards compatibility with Q2A 1.8.6 and before. + * @param string $charset + * @param string $collation + * @return string + */ +function qa_get_table_charset_collation($charset = QA_MYSQL_CHARSET, $collation = QA_MYSQL_COLLATION) +{ + $sql = 'DEFAULT CHARACTER SET ' . $charset; + if ($collation !== null) { + $sql .= ' COLLATE ' . $collation; + } + + return $sql; +} /** * Run the raw $query, call the global failure handler if necessary, otherwise return the result resource. diff --git a/qa-plugin/event-logger/qa-event-logger.php b/qa-plugin/event-logger/qa-event-logger.php index 4b7e72244..e01ede545 100644 --- a/qa-plugin/event-logger/qa-event-logger.php +++ b/qa-plugin/event-logger/qa-event-logger.php @@ -44,7 +44,7 @@ public function init_queries($table_list) 'KEY ipaddress (ipaddress),' . 'KEY userid (userid),' . 'KEY event (event)' . - ') ENGINE=MyISAM DEFAULT CHARSET=utf8'; + ') ENGINE=MyISAM ' . qa_get_table_charset_collation(); } else { // table exists: check it has the correct schema $column = qa_db_read_one_assoc(qa_db_query_sub('SHOW COLUMNS FROM ^eventlog WHERE Field="ipaddress"')); From b53aaa59a6c54e4d3ce2fc447c9ec63b6ec90ef0 Mon Sep 17 00:00:00 2001 From: pupi1985 Date: Sun, 18 Aug 2024 15:23:02 -0300 Subject: [PATCH 2/2] Remove explicit collations in tag queries --- qa-include/db/selects.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qa-include/db/selects.php b/qa-include/db/selects.php index 1a093ad7a..b5eefc94e 100644 --- a/qa-include/db/selects.php +++ b/qa-include/db/selects.php @@ -1218,7 +1218,7 @@ function qa_db_tag_recent_qs_selectspec($voteuserid, $tag, $start, $full = false $selectspec = qa_db_posts_basic_selectspec($voteuserid, $full); // use two tests here - one which can use the index, and the other which narrows it down exactly - then limit to 1 just in case - $selectspec['source'] .= " JOIN (SELECT postid FROM ^posttags WHERE wordid=(SELECT wordid FROM ^words WHERE word=$ AND word=$ COLLATE utf8_bin LIMIT 1) ORDER BY postcreated DESC LIMIT #,#) y ON ^posts.postid=y.postid"; + $selectspec['source'] .= " JOIN (SELECT postid FROM ^posttags WHERE wordid=(SELECT wordid FROM ^words WHERE word=$ AND word=$ LIMIT 1) ORDER BY postcreated DESC LIMIT #,#) y ON ^posts.postid=y.postid"; array_push($selectspec['arguments'], $tag, qa_strtolower($tag), $start, $count); $selectspec['sortdesc'] = 'created'; @@ -1235,7 +1235,7 @@ function qa_db_tag_word_selectspec($tag) { return array( 'columns' => array('wordid', 'word', 'tagcount'), - 'source' => '^words WHERE word=$ AND word=$ COLLATE utf8_bin', + 'source' => '^words WHERE word=$ AND word=$', 'arguments' => array($tag, qa_strtolower($tag)), 'single' => true, );