Skip to content

[3.0] Miscellaneous fixes for the installer and upgrader#9162

Merged
Sesquipedalian merged 45 commits into
SimpleMachines:release-3.0from
Sesquipedalian:3.0/upgrader
Jul 15, 2026
Merged

[3.0] Miscellaneous fixes for the installer and upgrader#9162
Sesquipedalian merged 45 commits into
SimpleMachines:release-3.0from
Sesquipedalian:3.0/upgrader

Conversation

@Sesquipedalian

@Sesquipedalian Sesquipedalian commented Mar 20, 2026

Copy link
Copy Markdown
Member

Fixes a bunch of stuff that has come up while testing the installer and upgrader.

@sbulen, we can use this PR to do all our testing to get 2.1 → 3.0 and 2.0 -> 3.0 upgrades fully working, as well as deal with any issues in the installer. Then we'll go back to #9120 afterward.

Fixes #9160

@sbulen

sbulen commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

So... Test here next???

@sbulen

sbulen commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

On this PR... Results are actually very good. Only a couple minor nits & questions.

2.1 => 3.0:

  • OK, no issues

Install: Ran fine. Only minor nits...

  • IIRC(?), In the past, if you didn't specify install.php in the url to invoke, but it was there, it would still run the installer. Now you have to explicitly invoke install.php - or you get an "Unable to establish connection" WSOD. A change in behavior, I think. Upgrader is detected OK.
  • Server Name doesn't pre-populate anymore... It's blank & you have to populate it.

General observations... These are both maybe just me & my system, not sure... Any thoughts would be welcome.

  • Installs & upgrades, especially on the initial welcome/config screens, are VERY VERY slow to paint... Doesn't feel normal. Once it starts it's OK. But it takes a while to get there. I've disabled xdebug, etc., things that normally slow down. Still crazy slow.
  • I haven't been able to get self-signed certs to be detected & work properly.

I think the performance is actually a 3.0 thing. I don't see that elsewhere.

I think the self-signed cert is a me thing... I see that elsewhere. No matter what I've tried, if I try to force https, I get sslRedirect within the app. And the installer never detects the cert, e.g., the ssl box is grayed out. I hate putzing with certs...

@sbulen

sbulen commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

I'd be OK with this going in as-is. Only nits.

@sbulen

sbulen commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

I could dive deeper & try 2.0 upgrades if needed.
And postgresql.
And I have MariaDB on a different port, that too.

Sound like a plan?

@Sesquipedalian

Copy link
Copy Markdown
Member Author

Install: Ran fine. Only minor nits...

  • IIRC(?), In the past, if you didn't specify install.php in the url to invoke, but it was there, it would still run the installer. Now you have to explicitly invoke install.php - or you get an "Unable to establish connection" WSOD. A change in behavior, I think. Upgrader is detected OK.

Hm. That's not good.

  • Server Name doesn't pre-populate anymore... It's blank & you have to populate it.

Should be an easy fix.

General observations... These are both maybe just me & my system, not sure... Any thoughts would be welcome.

  • Installs & upgrades, especially on the initial welcome/config screens, are VERY VERY slow to paint... Doesn't feel normal. Once it starts it's OK. But it takes a while to get there. I've disabled xdebug, etc., things that normally slow down. Still crazy slow.

I haven't noticed that in my tests, but I wasn't particularly looking for it either.

  • I haven't been able to get self-signed certs to be detected & work properly.

Yeah, that's probably just a you thing.

Rather than a self-signed certificate, why not just use one from Let's Encrypt?

@Sesquipedalian

Copy link
Copy Markdown
Member Author

I could dive deeper & try 2.0 upgrades if needed.

And postgresql.

And I have MariaDB on a different port, that too.

Sound like a plan?

Sounds like a great plan! Thanks, @sbulen. 😊

@sbulen

sbulen commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Rather than a self-signed certificate, why not just use one from Let's Encrypt?

Most of my testing is on localhost. Once things progress, I do final testing on a hosted test environment.

For a long time, no issues whatsoever, but browsers have been getting more picky over time. For years, a self-signed cert worked perfectly. Until it didn't... For a while there, I had to create my own CA for local use. Now, that is either unsupported, or, I'm doing it wrong...

@sbulen

sbulen commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

2.0 latin1 => 3.0:

image

php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:03:48+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\van2021\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\van2021\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\van2021/custom_avatar"... done.
Making sure SMF can write to "D:\wamp64\www\van2021/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats and force_ssl... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... done.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... done.
+++ Parsing board descriptions and names...

2.0 utf8 => 3.0:

image

php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:10:12+00:00
Step 1: Login
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats and force_ssl... done.
Saving the following settings in Settings.php: db_server and db_port... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... done.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... done.
+++ Parsing board descriptions and names...

pg => 3.0:

image

php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:26:46+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021/custom_avatar"... done.
Making sure SMF can write to "D:/wamp64/www/pgvan2021/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... failed with error: "ERROR: relation "admin_info_files" does not exist
LINE 1: ...files_seq', (SELECT COALESCE(MAX(id_file),1) FROM admin_info...
^"

MariaDB 11 => 3.0:

image

php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:36:50+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\11van21\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\11van21\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\11van21/custom_avatar"... done.
Making sure SMF can write to "D:/wamp64/www/11van21/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... skipped.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... skipped.
+++ Parsing board descriptions and names... skipped.
+++ Converting legacy attachments... skipped.
+++ Fixing invalid sizes on attachments... done.
+++ Fixing attachment directory setting... skipped.
+++ Adding support for logging who fulfils a group request... done.
+++ Adding new package manager columns... done.
+++ Adding support for validation servers... done.
+++ Adding more space for session ids... done.
+++ Adding support for MOVED topics enhancements... done.
+++ Adding new scheduled tasks... done.
+++ Adding background tasks support... done.
+++ Adding support for category descriptions... done.
+++ Adding support for alerts... done.
+++ Upgrading auto notify setting... done.
+++ Creating alert prefs for watched topics... done.
+++ Creating alert prefs for watched boards... done.
+++ Updating obsolete alerts from before RC3... done.
+++ Adding support for topic unwatch... done.
+++ Fixing mail queue for long messages... done.
+++ Altering the membergroup stars to icons... done.
+++ Updating Theme settings... done.
+++ Upgrade Custom Fields (Preparing)...

@Sesquipedalian

Copy link
Copy Markdown
Member Author

2.0 latin1 => 3.0:

image php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:03:48+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\van2021\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\van2021\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\van2021/custom_avatar"... done.
Making sure SMF can write to "D:\wamp64\www\van2021/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats and force_ssl... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... done.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... done.
+++ Parsing board descriptions and names...

2.0 utf8 => 3.0:

image php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:10:12+00:00
Step 1: Login
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats and force_ssl... done.
Saving the following settings in Settings.php: db_server and db_port... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... done.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... done.
+++ Parsing board descriptions and names...

These two should be fixed in the latest commits.

@Sesquipedalian

Sesquipedalian commented Mar 21, 2026

Copy link
Copy Markdown
Member Author

pg => 3.0:

image php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:26:46+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021/custom_avatar"... done.
Making sure SMF can write to "D:/wamp64/www/pgvan2021/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... failed with error: "ERROR: relation "admin_info_files" does not exist
LINE 1: ...files_seq', (SELECT COALESCE(MAX(id_file),1) FROM admin_info...
^"

Hm. Does the admin_info_files table not exist in the database before the upgrade starts?

@Sesquipedalian

Copy link
Copy Markdown
Member Author

MariaDB 11 => 3.0:

image php/apache/mysql logs: Nothing

upgrader log:

2026-03-20T17:36:50+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\11van21\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\11van21\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\11van21/custom_avatar"... done.
Making sure SMF can write to "D:/wamp64/www/11van21/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... skipped.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... skipped.
+++ Parsing board descriptions and names... skipped.
+++ Converting legacy attachments... skipped.
+++ Fixing invalid sizes on attachments... done.
+++ Fixing attachment directory setting... skipped.
+++ Adding support for logging who fulfils a group request... done.
+++ Adding new package manager columns... done.
+++ Adding support for validation servers... done.
+++ Adding more space for session ids... done.
+++ Adding support for MOVED topics enhancements... done.
+++ Adding new scheduled tasks... done.
+++ Adding background tasks support... done.
+++ Adding support for category descriptions... done.
+++ Adding support for alerts... done.
+++ Upgrading auto notify setting... done.
+++ Creating alert prefs for watched topics... done.
+++ Creating alert prefs for watched boards... done.
+++ Updating obsolete alerts from before RC3... done.
+++ Adding support for topic unwatch... done.
+++ Fixing mail queue for long messages... done.
+++ Altering the membergroup stars to icons... done.
+++ Updating Theme settings... done.
+++ Upgrade Custom Fields (Preparing)...

Bleh. Please run it again with this modified version of ./Sources/Maintenance/Migration/v2_1/CustomFieldsPart1.php. It will once again dump a bunch of crap into upgrade.log so I can figure out where things are going wrong.

<?php

/**
 * Simple Machines Forum (SMF)
 *
 * @package SMF
 * @author Simple Machines https://www.simplemachines.org
 * @copyright 2026 Simple Machines and individual contributors
 * @license https://www.simplemachines.org/about/smf/license.php BSD
 *
 * @version 3.0 Alpha 4
 */

declare(strict_types=1);

namespace SMF\Maintenance\Migration\v2_1;

use SMF\Db\DatabaseApi as Db;
use SMF\Db\Schema;
use SMF\Maintenance\Maintenance;
use SMF\Maintenance\Migration\MigrationBase;

class CustomFieldsPart1 extends MigrationBase
{
	/*******************
	 * Public properties
	 *******************/

	/**
	 *
	 */
	public string $name = 'Upgrade Custom Fields (Preparing)';

	/****************
	 * Public methods
	 ****************/

	/**
	 *
	 */
	public function execute(): bool
	{
		Maintenance::$tool->logProgress(__LINE__, true);
		$start = Maintenance::getCurrentStart();

		if ($start <= 0) {
			$table = new Schema\v2_1\CustomFields();
			Maintenance::$tool->logProgress(__LINE__, true);
			$table->normalize();
			Maintenance::$tool->logProgress(__LINE__, true);
			$this->handleTimeout(++$start);
		}

		if ($start <= 1) {
			Maintenance::$tool->logProgress(__LINE__, true);
			$table->populate();
			Maintenance::$tool->logProgress(__LINE__, true);
			$this->handleTimeout(++$start);
		}

		if ($start <= 2) {
			Maintenance::$tool->logProgress(__LINE__, true);
			// Add an order value to each existing cust profile field.
			$ocf = $this->query(
				'SELECT id_field
				FROM {db_prefix}custom_fields
				WHERE field_order = 0',
			);

			// We start counting from 5 because we already have the first 5 fields.
			$fields_count = 5;

			Maintenance::$tool->logProgress(__LINE__, true);
			while ($row = Db::$db->fetch_assoc($ocf)) {
				++$fields_count;

				Maintenance::$tool->logProgress($row['id_field'], true);
				$this->query(
					'UPDATE {db_prefix}custom_fields
					SET field_order = {int:field_count}
					WHERE id_field = {int:id_field}',
					[
						'field_count' => $fields_count,
						'id_field' => $row['id_field'],
					],
				);
			}
			Db::$db->free_result($ocf);

			Maintenance::$tool->logProgress(__LINE__, true);
			$this->handleTimeout(++$start);
		}

		return true;
	}
}

@Sesquipedalian
Sesquipedalian force-pushed the 3.0/upgrader branch 2 times, most recently from 2ab8fe3 to e9dbf3c Compare March 21, 2026 05:43
@sbulen

sbulen commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

Hm. Does the admin_info_files table not exist in the database before the upgrade starts?

Yes, the table exists, & the prefix is specified in Settings.php. It's a simple 2.1 install. I suspect the problem here, though, is that somehow the prefix was lost...

It's not "admin_info_files", it's "smf_admin_info_files".

@Sesquipedalian

Copy link
Copy Markdown
Member Author

Ah, yes. That would likely explain it. I'll take a look when I have time later.

@sbulen

sbulen commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

MariaDB 2.1 => 3.0:

Refreshed the code, implemented your tweak above & reattempted the upgrade. It actually got much further...

image

php/apache/mysql logs: Nothing

upgrader log (bottom):

+++ Parsing board descriptions and names... skipped.
+++ Add backtrace to log_error... skipped.
+++ Update permissions system board_permissions_view... done.
+++ Correct schema diff... skipped.
+++ Update holidays... done.
+++ Fix mods columns... done.
+++ Ensuring "smf_admin_info_files" is structured correctly... done.
+++ Ensuring "smf_approval_queue" is structured correctly... done.
+++ Ensuring "smf_attachments" is structured correctly... done.
+++ Ensuring "smf_background_tasks" is structured correctly... done.
+++ Ensuring "smf_ban_groups" is structured correctly...

@Sesquipedalian

Sesquipedalian commented Mar 29, 2026

Copy link
Copy Markdown
Member Author

It's not "admin_info_files", it's "smf_admin_info_files".

Should be fixed in latest commits.

MariaDB 2.1 => 3.0:

Refreshed the code, implemented your tweak above & reattempted the upgrade. It actually got much further...

image php/apache/mysql logs: Nothing

upgrader log (bottom):

+++ Parsing board descriptions and names... skipped.
+++ Add backtrace to log_error... skipped.
+++ Update permissions system board_permissions_view... done.
+++ Correct schema diff... skipped.
+++ Update holidays... done.
+++ Fix mods columns... done.
+++ Ensuring "smf_admin_info_files" is structured correctly... done.
+++ Ensuring "smf_approval_queue" is structured correctly... done.
+++ Ensuring "smf_attachments" is structured correctly... done.
+++ Ensuring "smf_background_tasks" is structured correctly... done.
+++ Ensuring "smf_ban_groups" is structured correctly...

Should be fixed in latest commits. If not, things might get a lot harder.

Ready for another round of testing, @sbulen. 🙂

@sbulen

sbulen commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

3.0 Install:

  • OK

2.1 => 3.0:

  • OK
  • Only observation here... I had a couple stupid issues on my side, too much coffee... When I restored & tried to start over, it thought I was further along than I was. E.g., there was no admin login screen, it started at the options screen. I had to delete my cookies to truly start over... That was a bit of a surprise... Possibly not an issue??? I gotta think about that...
  • Then, upon completion though, I was kicked out. I had to logon again to view the forum...
  • Everything else was fine.

2.0 latin1 => 3.0:

image

php/apache/mysql logs: Nothing

upgrade.log (bottom):

+++ Updating obsolete alerts from before RC3... done.
+++ Adding support for topic unwatch... done.
+++ Fixing mail queue for long messages... done.
+++ Altering the membergroup stars to icons... done.
+++ Updating Theme settings... done.
+++ Upgrade Custom Fields (Preparing)... done.
+++ Upgrade Custom Fields... done.
+++ Upgrade Custom Fields (Cleanup)... done.
+++ Adding support for drafts...

2.0 utf8 => 3.0:

image

php/apache/mysql logs: Nothing

upgrade.log (bottom):

+++ Adding support for validation servers... done.
+++ Adding more space for session ids... done.
+++ Adding support for MOVED topics enhancements... done.
+++ Adding new scheduled tasks... done.
+++ Adding background tasks support... done.
+++ Adding support for category descriptions... done.
+++ Adding support for alerts...

pg 2.1 => 3.0:

image

php/apache/mysql logs: Nothing

upgrade.log:

2026-04-02T19:52:28+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021/custom_avatar"... done.
Making sure SMF can write to "D:/wamp64/www/pgvan2021/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats... done.
Step 4: Migrations
 +++ Fixing sequences (PostgreSQL)... 

MariaDB11 2.1 => 3.0:

image
  • Note the weird display above... There weren't newlines betwen the steps in the display, it all went on one line....

php/apache/mysql logs: Nothing

upgrade.log (bottom):

+++ Adding new scheduled tasks... done.
+++ Adding background tasks support... done.
+++ Adding support for category descriptions... done.
+++ Adding support for alerts... done.
+++ Upgrading auto notify setting... done.
+++ Creating alert prefs for watched topics... done.
+++ Creating alert prefs for watched boards... done.
+++ Updating obsolete alerts from before RC3... done.
+++ Adding support for topic unwatch... done.
+++ Fixing mail queue for long messages... done.
+++ Altering the membergroup stars to icons... done.
+++ Updating Theme settings... done.
+++ Upgrade Custom Fields (Preparing)...

@Sesquipedalian

Copy link
Copy Markdown
Member Author

Thanks, @sbulen. It's been a while since I have been able to look at this PR again. I appreciate both your help and your patience.

2.0 latin1 => 3.0:

Should be fixed in latest commit.

2.0 utf8 => 3.0:

For diagnostic purposes, please run it again using this modified version of ./Sources/Maintenance/Migration/v2_1/CreateAlerts/php:

<?php

/**
 * Simple Machines Forum (SMF)
 *
 * @package SMF
 * @author Simple Machines https://www.simplemachines.org
 * @copyright 2026 Simple Machines and individual contributors
 * @license https://www.simplemachines.org/about/smf/license.php BSD
 *
 * @version 3.0 Alpha 4
 */

declare(strict_types=1);

namespace SMF\Maintenance\Migration\v2_1;

use SMF\Db\DatabaseApi as Db;
use SMF\Db\Schema;
use SMF\Maintenance\Maintenance;
use SMF\Maintenance\Migration\MigrationBase;

class CreateAlerts extends MigrationBase
{
	/*******************
	 * Public properties
	 *******************/

	/**
	 *
	 */
	public string $name = 'Adding support for alerts';

	/*********************
	 * Internal properties
	 *********************/

	/**
	 *
	 */
	private bool $is_done = false;

	/**
	 * @var int
	 *
	 * Maximum number of items to process at once.
	 */
	private int $limit = 10000;

	/****************
	 * Public methods
	 ****************/

	/**
	 *
	 */
	public function execute(): bool
	{
		Maintenance::$tool->logProgress(__LINE__, true);
		$members_table = new Schema\v2_1\Members();
		$user_alert_table = new Schema\v2_1\UserAlerts();
		$user_alert_prefs_table = new Schema\v2_1\UserAlertsPrefs();

		Maintenance::$tool->logProgress(__LINE__, true);
		$tables = Db::$db->list_tables();
		Maintenance::$tool->logProgress(__LINE__, true);

		if (!\in_array($user_alert_table->name, $tables)) {
			Maintenance::$tool->logProgress(__LINE__, true);
			$user_alert_table->create();
			Maintenance::$tool->logProgress(__LINE__, true);
		}

		if (!\in_array($user_alert_prefs_table->name, $tables)) {
			Maintenance::$tool->logProgress(__LINE__, true);
			$user_alert_prefs_table->create();
			Maintenance::$tool->logProgress(__LINE__, true);
		}

		Maintenance::$tool->logProgress(__LINE__, true);
		$existing_structure = $members_table->getCurrentStructure();

		foreach ($members_table->columns as $column) {
			Maintenance::$tool->logProgress(__LINE__, true);
			// Column exists, don't need to do this.
			if ($column->name !== 'alerts' || isset($existing_structure['columns'][$column->name])) {
				continue;
			}

			Maintenance::$tool->logProgress(__LINE__, true);
			$members_table->addColumn($column);
			Maintenance::$tool->logProgress(__LINE__, true);
		}

		// We don't need to increment the start, the column will exist and it should get past this.
		Maintenance::$tool->logProgress(__LINE__, true);
		$this->handleTimeout(0);
		Maintenance::$tool->logProgress(__LINE__, true);

		// Add our default permissions.
		Maintenance::$tool->logProgress(__LINE__, true);
		$user_alert_prefs_table->populate();
		Maintenance::$tool->logProgress(__LINE__, true);

		$request = $this->query(
			'SELECT COUNT(*)
			FROM {db_prefix}members',
			[],
		);

		list($maxMembers) = Db::$db->fetch_row($request);
		Maintenance::$total_items = (int) $maxMembers;

		Db::$db->free_result($request);

		// First see if we still have a notify_regularity column
		Maintenance::$tool->logProgress(__LINE__, true);
		$member_columns = Db::$db->list_columns('{db_prefix}members');

		if (\in_array('notify_regularity', $member_columns)) {
			Maintenance::$tool->logProgress(__LINE__, true);
			do {
				Maintenance::$tool->logProgress(__LINE__, true);
				$start = Maintenance::getCurrentStart();

				$this->handleTimeout($start);
				$inserts = [];

				// Skip errors here so we don't croak if the columns don't exist...
				Maintenance::$tool->logProgress(__LINE__, true);
				$request = $this->query(
					'SELECT id_member, notify_regularity, notify_send_body, notify_types, notify_announcements
					FROM {db_prefix}members
					ORDER BY id_member
					LIMIT {int:start}, {int:limit}',
					[
						'db_error_skip' => true,
						'start' => $start,
						'limit' => $this->limit,
					],
				);

				Maintenance::$tool->logProgress(__LINE__, true);
				if (Db::$db->num_rows($request) == 0) {
					break;
				}

				Maintenance::$tool->logProgress(__LINE__, true);
				while ($row = Db::$db->fetch_assoc($request)) {
					$inserts[] = [$row['id_member'], 'msg_receive_body', !empty($row['notify_send_body']) ? 1 : 0];
					$inserts[] = [$row['id_member'], 'msg_notify_pref', \intval($row['notify_regularity']) + 1];
					$inserts[] = [$row['id_member'], 'msg_notify_type', $row['notify_types']];
					$inserts[] = [$row['id_member'], 'announcements', !empty($row['notify_announcements']) ? 1 : 0];
				}

				Db::$db->free_result($request);

				Maintenance::$tool->logProgress(__LINE__, true);
				Db::$db->insert(
					'ignore',
					'{db_prefix}user_alerts_prefs',
					[
						'id_member' => 'int',
						'alert_pref' => 'string',
						'alert_value' => 'string',
					],
					$inserts,
					['id_member', 'alert_pref'],
				);
				Maintenance::$tool->logProgress(__LINE__, true);

				Maintenance::setCurrentStart($start + $this->limit);
				Maintenance::$tool->logProgress(__LINE__, true);
			} while (Maintenance::getCurrentStart() < Maintenance::$total_items);
		}

		Maintenance::$tool->logProgress(__LINE__, true);
		if (\in_array('notify_send_body', $member_columns)) {
			Maintenance::$tool->logProgress(__LINE__, true);
			Db::$db->remove_column('{db_prefix}members', 'notify_send_body');
			$this->handleTimeout();
		}

		Maintenance::$tool->logProgress(__LINE__, true);
		if (\in_array('notify_types', $member_columns)) {
			Maintenance::$tool->logProgress(__LINE__, true);
			Db::$db->remove_column('{db_prefix}members', 'notify_types');
			$this->handleTimeout();
		}

		Maintenance::$tool->logProgress(__LINE__, true);
		if (\in_array('notify_regularity', $member_columns)) {
			Maintenance::$tool->logProgress(__LINE__, true);
			Db::$db->remove_column('{db_prefix}members', 'notify_regularity');
			$this->handleTimeout();
		}

		Maintenance::$tool->logProgress(__LINE__, true);
		if (\in_array('notify_announcements', $member_columns)) {
			Maintenance::$tool->logProgress(__LINE__, true);
			Db::$db->remove_column('{db_prefix}members', 'notify_announcements');
			$this->handleTimeout();
		}

		Maintenance::$tool->logProgress(__LINE__, true);
		return true;
	}
}

pg 2.1 => 3.0:

For diagnostic purposes, please run it again using this modified version of ./Sources/Maintenance/Migration/v2_1/PostgreSqlSequences.php:

<?php

/**
 * Simple Machines Forum (SMF)
 *
 * @package SMF
 * @author Simple Machines https://www.simplemachines.org
 * @copyright 2026 Simple Machines and individual contributors
 * @license https://www.simplemachines.org/about/smf/license.php BSD
 *
 * @version 3.0 Alpha 4
 */

declare(strict_types=1);

namespace SMF\Maintenance\Migration\v2_1;

use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\Maintenance\Maintenance;
use SMF\Maintenance\Migration\MigrationBase;

class PostgreSqlSequences extends MigrationBase
{
	/*******************
	 * Public properties
	 *******************/

	/**
	 *
	 */
	public string $name = 'Fixing sequences (PostgreSQL)';

	/*********************
	 * Internal properties
	 *********************/

	/**
	 *
	 */
	private array $sequences = [
		[
			'key' => 'admin_info_files_seq',
			'table' => 'admin_info_files',
			'field' => 'id_file',
		],
		[
			'key' => 'attachments_seq',
			'table' => 'attachments',
			'field' => 'id_attach',
		],
		[
			'key' => 'ban_groups_seq',
			'table' => 'ban_groups',
			'field' => 'id_ban_group',
		],
		[
			'key' => 'ban_items_seq',
			'table' => 'ban_items',
			'field' => 'id_ban',
		],
		[
			'key' => 'boards_seq',
			'table' => 'boards',
			'field' => 'id_board',
		],
		[
			'key' => 'calendar_seq',
			'table' => 'calendar',
			'field' => 'id_event',
		],
		[
			'key' => 'calendar_holidays_seq',
			'table' => 'calendar_holidays',
			'field' => 'id_holiday',
		],
		[
			'key' => 'categories_seq',
			'table' => 'categories',
			'field' => 'id_cat',
		],
		[
			'key' => 'custom_fields_seq',
			'table' => 'custom_fields',
			'field' => 'id_field',
		],
		[
			'key' => 'log_actions_seq',
			'table' => 'log_actions',
			'field' => 'id_action',
		],
		[
			'key' => 'log_banned_seq',
			'table' => 'log_banned',
			'field' => 'id_ban_log',
		],
		[
			'key' => 'log_comments_seq',
			'table' => 'log_comments',
			'field' => 'id_comment',
		],
		[
			'key' => 'log_errors_seq',
			'table' => 'log_errors',
			'field' => 'id_error',
		],
		[
			'key' => 'log_group_requests_seq',
			'table' => 'log_group_requests',
			'field' => 'id_request',
		],
		[
			'key' => 'log_member_notices_seq',
			'table' => 'log_member_notices',
			'field' => 'id_notice',
		],
		[
			'key' => 'log_packages_seq',
			'table' => 'log_packages',
			'field' => 'id_install',
		],
		[
			'key' => 'log_reported_seq',
			'table' => 'log_reported',
			'field' => 'id_report',
		],
		[
			'key' => 'log_reported_comments_seq',
			'table' => 'log_reported_comments',
			'field' => 'id_comment',
		],
		[
			'key' => 'log_scheduled_tasks_seq',
			'table' => 'log_scheduled_tasks',
			'field' => 'id_log',
		],
		[
			'key' => 'log_spider_hits_seq',
			'table' => 'log_spider_hits',
			'field' => 'id_hit',
		],
		[
			'key' => 'log_subscribed_seq',
			'table' => 'log_subscribed',
			'field' => 'id_sublog',
		],
		[
			'key' => 'mail_queue_seq',
			'table' => 'mail_queue',
			'field' => 'id_mail',
		],
		[
			'key' => 'membergroups_seq',
			'table' => 'membergroups',
			'field' => 'id_group',
		],
		[
			'key' => 'members_seq',
			'table' => 'members',
			'field' => 'id_member',
		],
		[
			'key' => 'message_icons_seq',
			'table' => 'message_icons',
			'field' => 'id_icon',
		],
		[
			'key' => 'messages_seq',
			'table' => 'messages',
			'field' => 'id_msg',
		],
		[
			'key' => 'package_servers_seq',
			'table' => 'package_servers',
			'field' => 'id_server',
		],
		[
			'key' => 'permission_profiles_seq',
			'table' => 'permission_profiles',
			'field' => 'id_profile',
		],
		[
			'key' => 'personal_messages_seq',
			'table' => 'personal_messages',
			'field' => 'id_pm',
		],
		[
			'key' => 'pm_rules_seq',
			'table' => 'pm_rules',
			'field' => 'id_rule',
		],
		[
			'key' => 'polls_seq',
			'table' => 'polls',
			'field' => 'id_poll',
		],
		[
			'key' => 'scheduled_tasks_seq',
			'table' => 'scheduled_tasks',
			'field' => 'id_task',
		],
		[
			'key' => 'smileys_seq',
			'table' => 'smileys',
			'field' => 'id_smiley',
		],
		[
			'key' => 'spiders_seq',
			'table' => 'spiders',
			'field' => 'id_spider',
		],
		[
			'key' => 'subscriptions_seq',
			'table' => 'subscriptions',
			'field' => 'id_subscribe',
		],
		[
			'key' => 'topics_seq',
			'table' => 'topics',
			'field' => 'id_topic',
		],
	];

	/****************
	 * Public methods
	 ****************/

	/**
	 *
	 */
	public function isCandidate(): bool
	{
		return Db::$db->title === POSTGRE_TITLE;
	}

	/**
	 *
	 */
	public function execute(): bool
	{
		for ($i = Maintenance::getCurrentStart(); $i < \count($this->sequences); Maintenance::setCurrentStart()) {
			$this->handleTimeout();

			$value = $this->sequences[$i];
			Maintenance::$tool->logProgress(Config::varExport($value['key']), true);

			$this->query(
				"SELECT setval('{raw:key}', (SELECT COALESCE(MAX({raw:field}),1) FROM {raw:table}))",
				[
					'key' => Config::$db_prefix . $value['key'],
					'field' => $value['field'],
					'table' => Config::$db_prefix . $value['table'],
				],
			);
		}

		return true;
	}
}

MariaDB11 2.1 => 3.0:

For diagnostic purposes, please run it again using this modified version of ./Sources/Maintenance/Migration/v2_1/CustomFieldsPart1.php:

<?php

/**
 * Simple Machines Forum (SMF)
 *
 * @package SMF
 * @author Simple Machines https://www.simplemachines.org
 * @copyright 2026 Simple Machines and individual contributors
 * @license https://www.simplemachines.org/about/smf/license.php BSD
 *
 * @version 3.0 Alpha 4
 */

declare(strict_types=1);

namespace SMF\Maintenance\Migration\v2_1;

use SMF\Db\DatabaseApi as Db;
use SMF\Db\Schema;
use SMF\Maintenance\Maintenance;
use SMF\Maintenance\Migration\MigrationBase;

class CustomFieldsPart1 extends MigrationBase
{
	/*******************
	 * Public properties
	 *******************/

	/**
	 *
	 */
	public string $name = 'Upgrade Custom Fields (Preparing)';

	/****************
	 * Public methods
	 ****************/

	/**
	 *
	 */
	public function execute(): bool
	{
		$start = Maintenance::getCurrentStart();

		if ($start <= 0) {
			$table = new Schema\v2_1\CustomFields();
			Maintenance::$tool->logProgress(__LINE__, true);
			$table->normalize();
			Maintenance::$tool->logProgress(__LINE__, true);
			$this->handleTimeout(++$start);
		}

		if ($start <= 1) {
			Maintenance::$tool->logProgress(__LINE__, true);
			$table->populate();
			Maintenance::$tool->logProgress(__LINE__, true);
			$this->handleTimeout(++$start);
		}

		if ($start <= 2) {
			Maintenance::$tool->logProgress(__LINE__, true);
			// Add an order value to each existing cust profile field.
			$ocf = $this->query(
				'SELECT id_field
				FROM {db_prefix}custom_fields
				WHERE field_order = 0',
			);

			// We start counting from 5 because we already have the first 5 fields.
			$fields_count = 5;

			while ($row = Db::$db->fetch_assoc($ocf)) {
				++$fields_count;
				Maintenance::$tool->logProgress($row['id_field'] . ':' . $fields_count, true);

				$this->query(
					'UPDATE {db_prefix}custom_fields
					SET field_order = {int:field_count}
					WHERE id_field = {int:id_field}',
					[
						'field_count' => $fields_count,
						'id_field' => $row['id_field'],
					],
				);
			}
			Db::$db->free_result($ocf);

			$this->handleTimeout(++$start);
		}

		return true;
	}
}

@sbulen

sbulen commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Suggestion: Maybe we should just keep the debug stuff in there. That will help reduce back & forth. Consider even making it a switch. Can't have too much diagnostic info & options in these upgrades, IMO...

2.0 latin1 => 3.0:

image

php/apache/mysql logs: Nothing

upgrade.log:

2026-04-20T22:17:08+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\van2021\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\van2021\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\van2021/custom_avatar"... done.
Making sure SMF can write to "D:\wamp64\www\van2021/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats and force_ssl... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... done.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... done.
+++ Converting legacy attachments... done.
+++ Fixing invalid sizes on attachments... done.
+++ Fixing attachment directory setting... done.
+++ Adding support for logging who fulfils a group request... done.
+++ Adding new package manager columns... done.
+++ Adding support for validation servers... done.
+++ Adding more space for session ids... done.
+++ Adding support for MOVED topics enhancements... done.
+++ Adding new scheduled tasks... done.
+++ Adding background tasks support... done.
+++ Adding support for category descriptions... done.
+++ Adding support for alerts... done.
+++ Upgrading auto notify setting... done.
+++ Creating alert prefs for watched topics... done.
+++ Creating alert prefs for watched boards... done.
+++ Updating obsolete alerts from before RC3... done.
+++ Adding support for topic unwatch... done.
+++ Fixing mail queue for long messages... done.
+++ Altering the membergroup stars to icons... done.
+++ Updating Theme settings... done.
+++ Upgrade Custom Fields (Preparing)... done.
+++ Upgrade Custom Fields... done.
+++ Upgrade Custom Fields (Cleanup)... done.
+++ Adding support for drafts... done.
+++ Adding support for likes... done.
+++ Adding support for mentions... done.
+++ Adding support for group-based board moderation... done.
+++ Updating files that fetched from simplemachines.org... done.
+++ Upgrading "verification questions" feature... done.
+++ Updating profile permissions... done.
+++ Upgrading PM labels...

2.0 utf8 => 3.0:

image

php/apache/mysql logs: Nothing

upgrade.log:

2026-04-20T22:27:05+00:00
Step 1: Login
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats and force_ssl... done.
Saving the following settings in Settings.php: db_server and db_port... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... skipped.
+++ Add find_in_set function (PostgreSQL)... skipped.
+++ Time and date fixes... skipped.
+++ Adding new settings... done.
+++ Removing karma... done.
+++ Fixing dates... done.
+++ Creating login history table... done.
+++ Converting collapsed categories... done.
+++ Converting legacy attachments... done.
+++ Fixing invalid sizes on attachments... done.
+++ Fixing attachment directory setting... done.
+++ Adding support for logging who fulfils a group request... done.
+++ Adding new package manager columns... done.
+++ Adding support for validation servers... done.
+++ Adding more space for session ids... done.
+++ Adding support for MOVED topics enhancements... done.
+++ Adding new scheduled tasks... done.
+++ Adding background tasks support... done.
+++ Adding support for category descriptions... done.
+++ Adding support for alerts... 59... 64... 66... 69... 71... 75... 77... 80... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 90... 92... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 84... 96... 98... 101... 103... 117... 121... 123... 130... 143... 148... 158... 170... 173... 177... 179... 184... 186... 191... 193... 198... 200...

pg 2.1 => 3.0:

image

php/apache/mysql logs: Nothing

upgrade.log (portion - this went on for days...):

2026-04-20T22:40:32+00:00
Step 1: Login
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021\Settings_bak.php"... done.
Making sure SMF can write to "D:\wamp64\www\pgvan2021/custom_avatar"... done.
Making sure SMF can write to "D:/wamp64/www/pgvan2021/cache/db_last_error.php"... done.
Step 2: Upgrade Options
Saving the following settings in the settings table: enable_sm_stats... done.
Step 4: Migrations
+++ Fixing sequences (PostgreSQL)... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'... 'admin_info_files_seq'...

MariaDB11 2.1 => 3.0:

Doesn't look like if failed in the same place... Not sure why:

Note the weird display - all the debug lines are still on the same line, no line feeds:

image

php/apache/mysql logs: Nothing

upgrade.log (bottom only):
+++ Adding support for calendar events... skipped.
+++ Clean up indexes (Messages)... done.
+++ Clean up indexes (Topics)... done.
+++ Clean up indexes (Members)... done.
+++ Clean up indexes (Log Activity)... done.
+++ Clean up indexes (Log Packages)... done.
+++ Clean up indexes (Scheduled Tasks)... done.
+++ Clean up indexes (Admin Info Files)... done.
+++ Clean up indexes (Boards)... done.
+++ Clean up indexes (Log Comments)... done.
+++ Aligning legacy column data... done.
+++ Update smileys... done.
+++ Parsing board descriptions and names... skipped.
+++ Add backtrace to log_error... skipped.
+++ Update permissions system board_permissions_view... done.
+++ Correct schema diff... skipped.
+++ Update holidays... done.
+++ Fix mods columns... done.
+++ Ensuring "smf_admin_info_files" is structured correctly... done.
+++ Ensuring "smf_approval_queue" is structured correctly... done.
+++ Ensuring "smf_attachments" is structured correctly... done.
+++ Ensuring "smf_background_tasks" is structured correctly... done.
+++ Ensuring "smf_ban_groups" is structured correctly...

@sbulen

sbulen commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

A clue, not sure how much it helps....

The generic 'Critical Error' errors appear to be on the calls to handleTimeout() within a step. More likely to happen when attempting a restart.

Sometimes, it just seems to fall thru to exit... Trace follows...

This logic is new to me, but it seems to be checking for json in $_GET, that isn't there?

    3.3389    2682128                   -> SMF\Db\APIs\MySQL->query($db_string = 'ALTER TABLE smf_custom_fields\n\t\t\tCHANGE COLUMN `placement` `placement` tinyint NOT NULL DEFAULT 0', $db_values = ['security_override' => TRUE], $connection = ???, $identifier = ???) D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:1754
                                           => ++self::count D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:150
    3.3389    2682128                     -> str_contains($haystack = 'ALTER TABLE smf_custom_fields\n\t\t\tCHANGE COLUMN `placement` `placement` tinyint NOT NULL DEFAULT 0', $needle = '\'') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:152
    3.3389    2682128                     -> str_contains($haystack = 'ALTER TABLE smf_custom_fields\n\t\t\tCHANGE COLUMN `placement` `placement` tinyint NOT NULL DEFAULT 0', $needle = 'GROUP BY') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:157
    3.3390    2682128                     -> str_replace($search = [0 => '\\\\', 1 => '\\\'', 2 => '\'\''], $replace = [0 => '', 1 => '', 2 => ''], $subject = 'ALTER TABLE smf_custom_fields\n\t\t\tCHANGE COLUMN `placement` `placement` tinyint NOT NULL DEFAULT 0') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:175
    3.3390    2682128                     -> preg_replace($pattern = [0 => '~\'\\X*?\'~s', 1 => '~\\s+~s', 2 => '~/\\*!40001 SQL_NO_CACHE \\*/~', 3 => '~/\\*!40000 USE INDEX \\([A-Za-z\\_]+?\\) \\*/~', 4 => '~/\\*!40100 ON DUPLICATE KEY UPDATE id_msg = \\d+ \\*/~'], $replacement = [0 => ' %s ', 1 => ' ', 2 => '', 3 => '', 4 => ''], $subject = 'ALTER TABLE smf_custom_fields\n\t\t\tCHANGE COLUMN `placement` `placement` tinyint NOT NULL DEFAULT 0') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:176
    3.3390    2682256                     -> strtolower($string = 'ALTER TABLE smf_custom_fields CHANGE COLUMN `placement` `placement` tinyint NOT NULL DEFAULT 0') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:176
    3.3390    2682256                     -> trim($string = 'alter table smf_custom_fields change column `placement` `placement` tinyint not null default 0') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:176
    3.3390    2682256                     -> strpos($haystack = 'alter table smf_custom_fields change column `placement` `placement` tinyint not null default 0', $needle = '/*') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:186
    3.3390    2682256                     -> str_contains($haystack = 'alter table smf_custom_fields change column `placement` `placement` tinyint not null default 0', $needle = '--') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:187
    3.3390    2682256                     -> str_contains($haystack = 'alter table smf_custom_fields change column `placement` `placement` tinyint not null default 0', $needle = ';') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:188
    3.3390    2682256                     -> preg_match($pattern = '~(^|[^a-z])sleep($|[^[_a-z])~s', $subject = 'alter table smf_custom_fields change column `placement` `placement` tinyint not null default 0') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:190
    3.3391    2682256                     -> preg_match($pattern = '~(^|[^a-z])benchmark($|[^[a-z])~s', $subject = 'alter table smf_custom_fields change column `placement` `placement` tinyint not null default 0') D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:191
    3.3391    2682256                     -> SMF\Debug\DebugUtils::isDebugEnabled() D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:198
    3.3391    2682256                     -> mysqli_query($mysql = class mysqli { public $affected_rows = 20; public $client_info = 'mysqlnd 8.4.5'; public $client_version = 80405; public $connect_errno = 0; public $connect_error = NULL; public $errno = 0; public $error = ''; public $error_list = []; public $field_count = 7; public $host_info = 'localhost via TCP/IP'; public $info = NULL; public $insert_id = 0; public $server_info = '11.5.2-MariaDB'; public $server_version = 110502; public $sqlstate = '00000'; public $protocol_version = 10; public $thread_id = 564; public $warning_count = 0 }, $query = 'ALTER TABLE smf_custom_fields\n\t\t\tCHANGE COLUMN `placement` `placement` tinyint NOT NULL DEFAULT 0', $result_mode = 0) D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:215
    3.4692    2682304                     -> SMF\Debug\DebugUtils::isDebugEnabled() D:\wamp64\www\11van21\Sources\Db\APIs\MySQL.php:243
                                   => ++$start D:\wamp64\www\11van21\Sources\Maintenance\Migration\v2_1\CustomFieldsPart1.php:48
    3.4693    2665552             -> SMF\Maintenance\Migration\MigrationBase->handleTimeout($start = 1) D:\wamp64\www\11van21\Sources\Maintenance\Migration\v2_1\CustomFieldsPart1.php:48
    3.4693    2665552               -> SMF\Maintenance\Maintenance::setCurrentStart($start = 1) D:\wamp64\www\11van21\Sources\Maintenance\Migration\MigrationBase.php:72
    3.4694    2665392               -> SMF\Maintenance\Tools\ToolsBase->checkAndHandleTimeout() D:\wamp64\www\11van21\Sources\Maintenance\Migration\MigrationBase.php:75
    3.4694    2665392                 -> SMF\Maintenance\Maintenance::isOutOfTime() D:\wamp64\www\11van21\Sources\Maintenance\Tools\ToolsBase.php:550
    3.4694    2665392                   -> SMF\Sapi::isCLI() D:\wamp64\www\11van21\Sources\Maintenance\Maintenance.php:769
    3.4694    2665392                   -> SMF\Sapi::setTimeLimit($limit = 300) D:\wamp64\www\11van21\Sources\Maintenance\Maintenance.php:777
    3.4694    2665392                     -> set_time_limit($seconds = 300) D:\wamp64\www\11van21\Sources\Sapi.php:387
    3.4694    2665392                   -> SMF\Sapi::resetTimeout() D:\wamp64\www\11van21\Sources\Maintenance\Maintenance.php:778
    3.4694    2665392                     -> SMF\Sapi::isSoftware($server = 'apache') D:\wamp64\www\11van21\Sources\Sapi.php:400
    3.4695    2665648                       -> preg_match($pattern = '~apache~i', $subject = 'Apache/2.4.62 (Win64) OpenSSL/3.1.7 PHP/8.4.5 mod_fcgid/2.3.10-dev') D:\wamp64\www\11van21\Sources\Sapi.php:108
    3.4695    2665392                     -> function_exists($function = 'apache_reset_timeout') D:\wamp64\www\11van21\Sources\Sapi.php:400
    3.4695    2665392                   -> time() D:\wamp64\www\11van21\Sources\Maintenance\Maintenance.php:781
    3.4695    2665392                 -> SMF\Maintenance\Maintenance::isJson() D:\wamp64\www\11van21\Sources\Maintenance\Tools\ToolsBase.php:555
    3.4695    2665392                 -> SMF\Maintenance\Maintenance::isJson() D:\wamp64\www\11van21\Sources\Maintenance\Tools\ToolsBase.php:562
    3.4695    2665392                 -> SMF\Maintenance\Maintenance::exit($fallthrough = TRUE) D:\wamp64\www\11van21\Sources\Maintenance\Tools\ToolsBase.php:562
    3.4695    2665392                   -> exit() D:\wamp64\www\11van21\Sources\Maintenance\Maintenance.php:835
    3.4702    1757232

@sbulen

sbulen commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

OK, did some more sleuthing, & have a couple of things to share...

  1. The json issue... This is due to having a cached version of script.js. When you copy the 3.0 files over for the upgrade, if you had been running 2.1, then the old 2.1 .js files are still in browser cache... The 2.1 .js doesn't know to return.json()... Doing a couple hard refreshes prior to running the upgrader, and the display works properly (lines properly separated) and the Critical errors due to the fall-through stop happening.

I'm not quite sure what the fix is unless the upgrader can force a hard refresh to ensure new .js files are loaded.

I think this is causing all of the CRITICAL errors w/o messages.

  1. The expire_date issue... The issue here is that the command:
    ALTER TABLE smf_ban_groups CHANGE COLUMN expire_time expire_time int unsigned DEFAULT 'NULL';

...is being rejected in MariaDB. I'm not sure why exactly yet... Maybe a default or a SQL_MODE issue set for the session. Works OK without the quotes, but I see the same behavior in MySQL. Something appears to be making them behave differently at runtime.

@Sesquipedalian

Copy link
Copy Markdown
Member Author

That is all very helpful, @sbulen. Thanks! I'll see what I can do about them.

@sbulen

sbulen commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

I do see this in the browser console, it might help?
image

Signed-off-by: Jon Stovell <jonstovell@gmail.com>
Signed-off-by: Jon Stovell <jonstovell@gmail.com>
Signed-off-by: Jon Stovell <jonstovell@gmail.com>
@Sesquipedalian

Copy link
Copy Markdown
Member Author

That was helpful, @sbulen, thanks. I think the latest commits have solved that issue. When a timeout occurred, we were sending an empty response, which the JavaScript interpreted as an error. Now we send an appropriate JSON response.

@sbulen

sbulen commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

3.0 Install

Ran clean thru completion!

MySQL/php/apache logs: Clean

2.1 => 3.0

Ran clean thru completion!

Nits:

  • I had to logon, normally I'm just brought to the forum after an upgrade
  • Upgrade.php was still there, it wasn't deleted

MySQL/php/apache logs: Clean

Upgrade.log (bottom):

+++ Converting "smf_user_alerts" to utf8mb4... done.
+++ Converting "smf_user_alerts_prefs" to utf8mb4... done.
+++ Converting "smf_user_drafts" to utf8mb4... done.
+++ Converting "smf_user_likes" to utf8mb4... done.
Step 6: Cleanup
+++ Cleanup old files... skipped.
+++ Ensure name of Tasks directory is in correct case... done.
Step 7: Finalize Upgrade
Saving the following settings in the settings table: smfVersion... done.

2.0 latin1 => 3.0

image

MySQL/php/apache logs: Nothing

Upgrade.log (bottom):

+++ Ensuring "rul_log_comments" is structured correctly... done.
+++ Ensuring "rul_log_digest" is structured correctly... done.
+++ Ensuring "rul_log_errors" is structured correctly... done.
+++ Ensuring "rul_log_floodcontrol" is structured correctly... done.
+++ Ensuring "rul_log_group_requests" is structured correctly... done.
+++ Ensuring "rul_log_mark_read" is structured correctly... done.
+++ Ensuring "rul_log_member_notices" is structured correctly... done.
+++ Ensuring "rul_log_notify" is structured correctly... done.
+++ Ensuring "rul_log_online" is structured correctly...

2.0 utf8 => 3.0

Odd, this is the first thing that pops up, none of the normal welcome banners, login, etc. I repeated this test a couple times, same results:

image

MySQL/php/apache logs: Nothing

Upgrade.log (complete):

2026-06-27T17:30:46+00:00
Step 1: Login

@Sesquipedalian

Sesquipedalian commented Jun 28, 2026

Copy link
Copy Markdown
Member Author

2.0 latin1 => 3.0

image MySQL/php/apache logs: Nothing

Upgrade.log (bottom):

+++ Ensuring "rul_log_comments" is structured correctly... done.
+++ Ensuring "rul_log_digest" is structured correctly... done.
+++ Ensuring "rul_log_errors" is structured correctly... done.
+++ Ensuring "rul_log_floodcontrol" is structured correctly... done.
+++ Ensuring "rul_log_group_requests" is structured correctly... done.
+++ Ensuring "rul_log_mark_read" is structured correctly... done.
+++ Ensuring "rul_log_member_notices" is structured correctly... done.
+++ Ensuring "rul_log_notify" is structured correctly... done.
+++ Ensuring "rul_log_online" is structured correctly...

Ugh, these wretched IP columns!

Can you show me the CREATE TABLE statement for the rul_log_online table from that database before you started the upgrade, and again immediately after that error occurs? I want to see what its structure looks like before and after.

@Sesquipedalian

Copy link
Copy Markdown
Member Author

2.0 utf8 => 3.0

Odd, this is the first thing that pops up, none of the normal welcome banners, login, etc. I repeated this test a couple times, same results:

image MySQL/php/apache logs: Nothing

Upgrade.log (complete):

2026-06-27T17:30:46+00:00
Step 1: Login

Was there an errant $upgradeData = ... in the Settings.php file before you started?

@sbulen

sbulen commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Can you show me the CREATE TABLE statement for the rul_log_online table from that database before you started the upgrade, and again immediately after that error occurs? I want to see what its structure looks like before and after.

BEFORE (Restored from a fresh 2.0 install without the utf8 box checked, matches install definition):

CREATE TABLE rul_log_online (
session varchar(32) NOT NULL DEFAULT '',
log_time int NOT NULL DEFAULT '0',
id_member mediumint unsigned NOT NULL DEFAULT '0',
id_spider smallint unsigned NOT NULL DEFAULT '0',
ip int unsigned NOT NULL DEFAULT '0',
url text NOT NULL,
PRIMARY KEY (session),
KEY log_time (log_time),
KEY id_member (id_member)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

AFTER (After upgrade attempt - note it didn't get as far as utf8 conversion):

CREATE TABLE rul_log_online (
session varchar(128) NOT NULL DEFAULT '',
log_time bigint NOT NULL DEFAULT '0',
id_member mediumint unsigned NOT NULL DEFAULT '0',
id_spider smallint unsigned NOT NULL DEFAULT '0',
ip varbinary(16) NOT NULL DEFAULT '0x30783330',
url varchar(2048) NOT NULL DEFAULT '',
PRIMARY KEY (session),
KEY log_time (log_time),
KEY id_member (id_member),
KEY idx_log_time (log_time),
KEY idx_id_member (id_member)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC

That default value looks sketchy - note it would be "0x30".... Which looks like we were aiming for "0x0"...

Also note the InnoDB conversion was completed? I thought that came later....

@sbulen

sbulen commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Was there an errant $upgradeData = ... in the Settings.php file before you started?

Sorry about that - must've been... I swear I double-checked that & repeated the test. Acting normal today...

PEBKAC... (There was NO beer involved, I swear...)

The utf8 test now behaves like the latin1 test, which is a good thing:

image

@Sesquipedalian

Sesquipedalian commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

Can you show me the CREATE TABLE statement for the rul_log_online table from that database before you started the upgrade, and again immediately after that error occurs? I want to see what its structure looks like before and after.

BEFORE (Restored from a fresh 2.0 install without the utf8 box checked, matches install definition):

CREATE TABLE rul_log_online (
session varchar(32) NOT NULL DEFAULT '',
log_time int NOT NULL DEFAULT '0',
id_member mediumint unsigned NOT NULL DEFAULT '0',
id_spider smallint unsigned NOT NULL DEFAULT '0',
ip int unsigned NOT NULL DEFAULT '0',
url text NOT NULL,
PRIMARY KEY (session),
KEY log_time (log_time),
KEY id_member (id_member)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

AFTER (After upgrade attempt - note it didn't get as far as utf8 conversion):

CREATE TABLE rul_log_online (
session varchar(128) NOT NULL DEFAULT '',
log_time bigint NOT NULL DEFAULT '0',
id_member mediumint unsigned NOT NULL DEFAULT '0',
id_spider smallint unsigned NOT NULL DEFAULT '0',
ip varbinary(16) NOT NULL DEFAULT '0x30783330',
url varchar(2048) NOT NULL DEFAULT '',
PRIMARY KEY (session),
KEY log_time (log_time),
KEY id_member (id_member),
KEY idx_log_time (log_time),
KEY idx_id_member (id_member)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC

That default value looks sketchy - note it would be "0x30".... Which looks like we were aiming for "0x0"...

Yup, I agree.

Latest commit explicitly sets the default to null for all inet columns (except for smf_log_flood_control.ip, which cannot be null). I think that will resolve this problem.

Signed-off-by: Jon Stovell <jonstovell@gmail.com>
@sbulen

sbulen commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

3.0 Install

Ran clean thru completion!

MySQL/php/apache logs: Clean

2.1 => 3.0

Ran clean thru completion!

Nits:

  • I had to logon, normally I'm just brought to the forum after an upgrade
  • Upgrade.php was still there, it wasn't deleted

MySQL/php/apache logs: Clean

2.0 latin1 => 3.0

Still getting this, no idea why:
image

DB - Note the other changes are in place, e.g., the session size doesn't match 2.0, nor does the URL definition or log_time. So the other changes are happening OK:
image

Note the default looks null in the code, both the 2.1 branch & the 3.0 branch:
image

So, no idea where the 0x30 thing is coming from.

MySQL/php/apache logs: Nothing

@sbulen

sbulen commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Observation on the IP size issue: We can't just put the target 3.0 definition out there for the IPs...

There's a whole conversion from ipv4 to ipv6 that needs to take place, that took place between 2.0 & 2.1. Until that takes place, the ipv4 definition needs to stand. (Which goes back to my old concern that some of these need to go stepwise thru SMF versions, like the old model...) Note the old 2.0 default is '0', which is where I suspect the 0x30 is ultimately coming from.

The tables that look OK (log_errors) are empty. BUT... The definition looks good.

Other random observation: log_online has this step, which the other records don't:

Update log_online ip with ipv6 support without converting... done.

Signed-off-by: Jon Stovell <jonstovell@gmail.com>
@Sesquipedalian

Copy link
Copy Markdown
Member Author

Update log_online ip with ipv6 support without converting... done.

That led me to go back and look again at the old upgrade_2-1_mysql.sql file. As it turns out, the approach taken there was to drop the column and then add it back again with an updated definition. I'm going to guess that this was done in order to avoid the same issue we've been facing here.

Latest commit follows the same drop-and-add strategy.

This was no longer used for anything in SMF 2.1, but the column was retained in the members table.

Signed-off-by: Jon Stovell <jonstovell@gmail.com>
@Sesquipedalian

Copy link
Copy Markdown
Member Author

@sbulen, do you think you will have time to test this again in the next little while? I'd really like to put this one to bed.

@sbulen

sbulen commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

3.0 Install

Ran clean thru completion, but with this error:

image

These errors occur upon every screen refresh within the app.

MySQL/php/apache logs: the php log includes the above error

2.1 => 3.0

Ran clean thru completion!

Note the same error occurs: Undefined array key "secureCookies" navigating the forum.

Nits:

  • I had to logon, normally I'm just brought to the forum after an upgrade
  • Upgrade.php was still there, it wasn't deleted

MySQL/php/apache logs: the php log includes the above error

Let me know if you want me to power ahead, or if you want to tweak this first.

@Sesquipedalian

Sesquipedalian commented Jul 14, 2026

Copy link
Copy Markdown
Member Author

Undefined array key "secureCookies" navigating the forum.

That makes absolutely no sense to me. That line hasn't changed since 2023, and it looks like this:

		$this->secure = $secure ?? !empty(Config::$modSettings['secureCookies']);

It's wrapped in a call to empty(), so it makes no sense that it would complain about the key being undefined. Can you check whether that line is the same in your code?

At any rate, I find it hard to believe this has anything to do with the upgrader directly.

EDIT: I think you must have had some mixed code in there. Line 208 in ./Sources/Cookie.php did change in 81b9abf, but that commit isn't part of this branch. It will need to be fixed, but it's not part of this PR.

Let me know if you want me to power ahead, or if you want to tweak this first.

Yes, please keep going.

@sbulen

sbulen commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Clarification: I refresh & rebuild before every round of testing, & always have. For any PR, including my own. I need to test what would happen if the PR were merged today, not weeks/months ago... (The upgrader borrows many functions from /Sources.) So the 'secure cookies' errors appear in all tests below, in the SMF & php error logs.

Good news: IMO, I think we're close enough to merge & treat the remaining issues standalone.

Only one outstanding hard issue with PG.

Minor nits in logon post conversion, as reported earlier.

If you want to push ahead, I'll log the above separately.

3.0 Install

Ran clean thru completion & forum works fine!

MySQL/php/apache logs: Clean

2.1 => 3.0

Ran clean thru completion & forum works fine!

Nits:

  • I had to logon, normally I'm just brought to the forum after an upgrade
  • Upgrade.php was still there, it wasn't deleted

MySQL/php/apache logs: Clean

Upgrade log: Clean

2.0 latin1 => 3.0

Ran clean thru completion & forum works fine!

*** log_online structure looks good, matches install (varbinary(16) NULL).

Nits:

  • I had to logon, normally I'm just brought to the forum after an upgrade

Upgrade.php deleted properly (unlike 2.1 => 3.0 above).

MySQL/php/apache logs: Clean

Upgrade log: Clean

2.0 utf8 => 3.0

Ran clean thru completion & forum works fine!

*** log_online structure looks good, matches install (varbinary(16) NULL).

Nits:

  • I had to logon, normally I'm just brought to the forum after an upgrade

Upgrade.php deleted properly (unlike 2.1 => 3.0 above).

MySQL/php/apache logs: Clean

Upgrade log: Clean

2.1 MariaDB => 3.0

Ran clean thru completion & forum works fine!

Interesting:

  • I did NOT have to logon like the others..., I was just brought to the forum already logged on after the upgrade like normal.
  • Upgrade.php deleted properly.

MySQL/php/apache logs: Clean

Upgrade log: Clean

2.1 PG => 3.0

image

MySQL/php/apache logs: Clean

Upgrade log (bottom):

+++ Adding support for category descriptions... done.
+++ Adding support for alerts... done.
+++ Upgrading auto notify setting... done.
+++ Creating alert prefs for watched topics... done.
+++ Creating alert prefs for watched boards... done.
+++ Updating obsolete alerts from before RC3... failed with error: "ERROR: invalid input syntax for type bigint: "topic"
LINE 2: SET content_id = 'topic',
^"

@sbulen

sbulen commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Update: I was trying to drill down on the composer error reported earlier, & I discovered that that error, plus the null error, were both from BEFORE the upgrade...

What I think happened was that I had 2.1.7 forum up in the background while copying the 3.0 files over on top of the 2.1.7 code (mimicking an upgrade); I hadn't yet copied upgrade.php to root. Index.php was invoked in that mixed state. (I suspect either the ajax alert popup, or a brain fart on my part pulling up the tab too soon...)

TL;DR, I reran both MariaDB & Postgresql this am, without 2.1.7 running in the background, and there were no null or composer errors. I updated the report above accordingly.

@Sesquipedalian

Sesquipedalian commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

Lovely! Thank you, @sbulen. I agree that it makes sense to merge now and deal with remaining problems separately. Please do report those remaining problems as their own issues.

I really appreciate your faithful testing of all these changes, my friend!

@Sesquipedalian
Sesquipedalian merged commit 5628a7a into SimpleMachines:release-3.0 Jul 15, 2026
4 checks passed
@Sesquipedalian
Sesquipedalian deleted the 3.0/upgrader branch July 15, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[3.0]: "Invalid default value for 'expire_time'" when running upgrade.php

3 participants