On 8/12/22 11:40, Eric Bollengier via Bacula-devel wrote:
Hello Phil,

On 8/12/22 16:45, Phil Stracchino wrote:

minbar:root:/usr/libexec/bacula:16 # ./update_mysql_tables

This script will update a Bacula MySQL database
   from any from version 12-15 or 1014-1022 to version 1024
   which is needed to convert from any Bacula Community
   versions 5.0.x, 5.2.x, 7.4.x, 9.x.x to Community version 11.4

Depending on the current version of your catalog, you may
   have to run this script multiple times

ERROR 1068 (42000) at line 3: Multiple primary key defined
ERROR 1061 (42000) at line 6: Duplicate key name 'object_type_idx'
Update of Bacula MySQL tables 1022 to 1023 succeeded.


Investigating...


Thanks for the valuable feedback.


The first failure above (line 3) was because there was already a primary key
defined on the table.

Do this instead:
ALTER TABLE FileMedia DROP PRIMARY KEY,
      ADD FileMediaId INT AUTO_INCREMENT PRIMARY KEY;

I don't see which query to replace with this one, the FileMedia doesn't have
a primary key defined (created in step 1022). Is MySQL taking the index defined
on JobId,Fileindex as the primary key ? (would be a bit strange).

DOH!!!   I misread.
That's line 3. Line 3 is NOT the FileMedia table, which is why I was unable to reproduce this error on a copy of the FileMedia table restored from last night's DB backup.

The offending command is not:

ALTER TABLE FileMedia ADD FileMediaId integer auto_increment primary key;

It's this, I believe:

ALTER TABLE JobHisto MODIFY COLUMN JobId int PRIMARY KEY AUTO_INCREMENT;

And if I test THIS against a copy restored from the last backup...


MySQL 127.0.0.1> CREATE TABLE `JobHisto` (
    ->   `JobId` int(10) unsigned NOT NULL,
    ->   `Job` varbinary(64) NOT NULL,
    ->   `Name` varbinary(96) NOT NULL,
    ->   `Type` binary(1) NOT NULL,
    ->   `Level` binary(1) NOT NULL,
    ->   `ClientId` int(11) DEFAULT 0,
    ->   `JobStatus` binary(1) NOT NULL,
    ->   `SchedTime` datetime DEFAULT NULL,
    ->   `StartTime` datetime DEFAULT NULL,
    ->   `EndTime` datetime DEFAULT NULL,
    ->   `RealEndTime` datetime DEFAULT NULL,
    ->   `JobTDate` bigint(20) unsigned DEFAULT 0,
    ->   `VolSessionId` int(10) unsigned DEFAULT 0,
    ->   `VolSessionTime` int(10) unsigned DEFAULT 0,
    ->   `JobFiles` int(10) unsigned DEFAULT 0,
    ->   `JobBytes` bigint(20) unsigned DEFAULT 0,
    ->   `ReadBytes` bigint(20) unsigned DEFAULT 0,
    ->   `JobErrors` int(10) unsigned DEFAULT 0,
    ->   `JobMissingFiles` int(10) unsigned DEFAULT 0,
    ->   `PoolId` int(10) unsigned DEFAULT 0,
    ->   `FileSetId` int(10) unsigned DEFAULT 0,
    ->   `PriorJobId` int(10) unsigned DEFAULT 0,
    ->   `PurgedFiles` tinyint(4) DEFAULT 0,
    ->   `HasBase` tinyint(4) DEFAULT 0,
    ->   `HasCache` tinyint(4) DEFAULT 0,
    ->   `Reviewed` tinyint(4) DEFAULT 0,
    ->   `Comment` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
    ->   `FileTable` char(20) COLLATE utf8mb4_unicode_ci DEFAULT 'File',
    ->   `PriorJob` tinyblob DEFAULT NULL,
    ->   PRIMARY KEY (`JobId`),
    ->   KEY `StartTime` (`StartTime`),
    ->   KEY `jobtdate_idx` (`JobTDate`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
Query OK, 0 rows affected (0.090 sec)

MySQL 127.0.0.1> ALTER TABLE JobHisto MODIFY COLUMN JobId int PRIMARY KEY AUTO_INCREMENT;
ERROR 1068 (42000): Multiple primary key defined
MySQL 127.0.0.1>


Bingo.  There's the problem line.

Though ... since JobIds come from the Job table it's not clear to me why we're even making this change, since Job.JobId is still an INT UNSIGNED. Surely JobHisto.JobId should ALSO be an INT INSIGNED? And since values are copied to it from the Job table it should not be AUTO_INCREMENT. JobId values should get autoincremented once, in the Job table when they are created, and nowhere else. The JobId column is an INT UNSIGNED in every other table (except PathVisibility, in which it is *also* erroneously a signed INT(11)).

I would just remove that ALTER directive, period. It is unnecessary and wrong. What we OUGHT to be doing there is changing PathVisibility.JobId to the correct INT UNSIGNED.


The second operation (line 6) failed because the index you told mysql to create
already existed.  There is already an index object_type_idx over ObjectType,
then you tried to create a second index ALSO called object_type_idx over
ObjectCategory:

ALTER TABLE Object ADD ObjectCategory TINYBLOB NOT NULL;
create index object_type_idx on Object  (ObjectCategory(255));

I'm presuming that new index was meant to be object_category_idx.  Also, it's
pointless to specify an index field length that's the same size as the column,
and mysql quite sensibly ignores the length specification because it is a NOOP.

I believe it's done this way because in the past it was mandatory. Maybe it is
not anymore, but between all flavors and versions, I rather prefer a NOOP
operation versus a syntax error.

Oh sure, it's harmless, it's just unnecessary considering that the TINYBLOB type is a maximum of 255 bytes in the first place. The real problem there is the presumed typo (object_type_idx in place of object_category_idx) that results in trying to create an index that already exists.

Also, it makes more clear that only the first 255 bytes are used in the index,
which can cause errors when the index has the UNIQUE property. Do you know if
it's still the case?

A length-restricted index can be UNIQUE without causing problems, that's fine as long as there are no NULLs. The differences between PRIMARY and UNIQUE are:

- A table can (and should) have only one PRIMARY key, but may have multiple UNIQUE keys - A PRIMARY key is not permitted to contain NULLABLE columns, while a UNIQUE key CAN contain NULLable columns, but UNIQUE processing *stops* at the first NULL encountered in any covered column of the index.

Otherwise their semantics are identical.


The script then terminated after incorrectly reporting update to 1023 succeeded,
but did not go on to update to 1024, and will not separately update 1023 to 1024
because it says it cannot update 1023.  So as it now exists, this script will
leave you stuck at version 1023 which neither 11.x nor 13.x will run on.  After
fixing the errors above, I had to manually apply the 1024 update section.  (With
corrections.)

It is done on purpose, if a part of the upgrade doesn't work, we cannot
continue. With PostgreSQL, we use BEGIN/COMMIT to make sure to rollback
to the previous state if one single operation cannot be done. Here, all
operations up to the error point are done and cannot be undone, so the
user has to edit the upgrade script manually.

Then why not use BEGIN/COMMIT in the mysql update as well?

I mean, true, BEGIN/COMMIT is not supported on MYISAM tables. But at this point anyone running a post-2010 version of MySQL is running InnoDB (or its improved Percona or MariaDB versions) by default *anyway* unless they *deliberately took active steps* to change their default back to MyISAM. I imagine the performance of Bacula on MyISAM tables would be terrible, because the performance of *anything* non-trivial on MyISAM tables is terrible. It should have been obsoleted and removed at least fifteen years ago. People forget that one of the principal design constraints for the MyISAM storage engine was that it needed to provide *acceptable* performance on a small, shared PC server, in an age when a large PC server was one that had a whole 32MB of RAM.



According to my notes:
"We use BLOB rather than TEXT because in MySQL, BLOBs are identical to TEXT
except that BLOB is case sensitive in sorts, which is what we want, and TEXT
is case insensitive."

That's actually not strictly correct. TEXT columns are sorted according to the charset collation in use, while BLOB columns are sorted on pure byte values. This has a more-or-less-accidental side effect of making SORTs on string values in BLOBs case sensitive. You can achieve the same case-sensitive searching on a TEXT field by using ORDER BY BINARY ... instead or a simple ORDER BY ... on the column.

But VARCHAR and VARBINARY have the exact same differences between them as TEXT and BLOB, so that behavior would transfer. The only functional differences between a TINYBLOB and a VARBINARY(255) is that a VARBINARY can be in a MEMORY table, which any BLOB cannot, and can (and should) have a DEFAULT value while a BLOB cannot.

You can do the same thing with VARCHARs, using ORDER BY BINARY ... but then you effectively have a VARBINARY, so you may as well just declare it as a VARBINARY in the first place.


...Shouldn't that say 13.0, not 11.4?

Yes of course, thanks for the feedback

Best Regards,
Eric

Sorry for the delay after release finding this, btw; Gentoo's app-backup/bacula went straight from 11.0.6-r2 to 13.0.1, which only appeared today, and I've been too busy to pull and test manual builds.



--
  Phil Stracchino
  Babylon Communications
  ph...@caerllewys.net
  p...@co.ordinate.org
  Landline: +1.603.293.8485
  Mobile:   +1.603.998.6958


_______________________________________________
Bacula-devel mailing list
Bacula-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bacula-devel

Reply via email to