-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
MySQL/MariDB broken on default Debian installations #377
Comments
Is there an alternative to "latin1"? I'd like to keep utf8 because we store json data which is (usually) utf8 encoded |
Is reducing the key size a possibility? uuid use 32 only anyways so if we quadrupel that (128) we're still ready for some long af keys |
Another issue is that we need to alter the table's charset which may cause cruel conversion errors (at least that was the case a few years ago) which are really hard to recover from (LAMP nightmares). So I'd like to find a solution that is less prone to error. |
well, the only issue is the primary key .. if that's not a VARCHAR(255) in actuality, it shouldn't be stored as such ... if it's actually a UUID it might be worth looking at http://mysqlserverteam.com/storing-uuid-values-in-mysql-tables/ - there are some serious performance improvements possible, but it goes for one hell of a migration (once) .. and the charset could be kept. |
The issue is that the default id generation is uuid but it can be overriden by the user in some cases (e.g. clients), so we can't force uuid here, unfortunately. |
But would reducing the key size resolve the issue described? |
It should, if it's reduced below 767 effective bytes, making it VARCHAR(191) .. 191*4 = 764 .. |
One difficulty is that we don't know the primary key constraint's name, as it was not forced during table construction:
I'm not sure if the index name is the same on mysql/mariadb/postgres across versions. So I actually don't know how to write a |
Hmm. Not really. Existing tables should also be fine, so no need to alter them. Don't know whether the DB layer can live with differences there, though ;) CREATE for a new table on a system with issues will simply fail. |
Yeah that makes sense. I don't think it would be wise to have different versions around. It might make sense to fix that for the 1.0.0 release and let people know who used prior versions that they need to upgrade the key length themselves. |
Creating and updating database schemas is now a separate command ( |
I just ran into this as well while trying to initialize a new hydra db. In order to enable large key support by default, you need to set: Unfortunately, innodb_default_row_format isn't available as an option until MySQL 5.7, and RDS Aurora (which is what I'm using) only supports MySQL 5.6, so I can't enable large key support by default on RDS Aurora. There are several options:
To get started I'm going with option 1, but option 2 would be really nice if the keys don't really need to be over 191 characters. I'd be happy to submit a PR to reduce the VARCHAR(255) statements to VARCHAR(191), but I don't know if that would break anything. |
Yeah this should definitely be addressed in the 0.10.0 branch. I think |
Ok, I'll put something together next week. |
An alternative would be to move the current primary key to a surrogate key with a unique index and use a (maybe unqueriable) auto-increment INT primary key. That way we could even allow larger keys than 255 for the surrogate key whilst being nice to ops and generally more interoperable. What do you think? |
I want to quickly re-iterate my reasoning here:
|
Here's a quick PR I drafted out for showing you what I mean by that exactly: #642 Please note that this is only PostgreSQL so far but it should be equally easy for mysql. |
I hit this too over the weekend. Doesn't work on mySQL5.6, but works fine on mySQL5.7 I looked over your change and think that is a neat way to get around the size problem without having to reduce the length of the keys. Would be nice to mention somewhere this limitation until the fix is committed. |
I agree that this should be addressed, I'm currently preoccupied with some other things but I definitely want this to land in 0.10.0 |
If I'm reading the PR correctly, it looks like this line |
Oh snap, that is truly unfortunate. We certainly shouldn't remove indices from the |
I think we could live with going for 191 length |
If you think we can live with 191 length for surrogate_id, that's a pretty straightforward migration. I can build on your PR and alter the tables to make surrogate_id varchar(191) if you like. What do you think? |
I would love that! Before you start, how would you migrate FOREIGN KEY relations? We have two modules using those:
I think that, if you solve the migration for the first module, the second module will work the same way. My idea so far was to (table A being the table, that table B has a foreign relation to):
|
I reviewed all of the table keys and constraints that need to be modified: KEYS CONSTRAINTS I'm starting to have concerns about whether shortening the key lengths will work, because we're not just shortening id to 191. Some keys have to be shortened to 95. I don't know the code well enough to say whether shortening has the possibility of truncating keys. Here what would need to happen:
Note that in the hydra_jwk table, the sid and kid fields would have to be reduced to 95 each since the key includes both fields, similarly in the hydra_warden_group_member table, the member and group_id fields would have to be reduced to 95 each. The compiled and template fields in three tables would have to be reduced from 512 characters to 191. And the policy field would have to be reduced to 127 since the keys include policy and another 64-character field. Is this reducing the fields too much? If not, I will write a PR to shorten the keys in this way, along with renaming id to surrogate_id, introducing a new id field, and dropping and re-adding the foreign-key constraints. Other possible approaches:
Which is the best approach? |
Thank you for the thorough investigation! Reducing some of those keys that drastically is indeed a bit tricky, especially with the compiled fields in ladon_action/ladon_resource etc. Regarding some of the others:
We could split those into two columns, right?
Is this due to the composed primary key? One question I have though is, we're using MySQL 5.7 from library/docker for integration tests - why aren't those catching these issues? |
The hydra_jwk table has a combined key: sid + kid. If we split this into two separate (non-unique) keys, then each key could be 191 bytes long. Does the database have to enforce that sid + kid be unique? If not, then creating two separate non-unique keys is the way to go. A similar question applies to the hydra_warden_group_member table, which currently has a combined key of member + group_id. If the database doesn't have to enforce that member + group_id be unique, then we could create two separate keys here and allow member and group_id to be 191 bytes long. The reason that Hydra works in MySQL 5.7 is that the four fields that I mentioned all have the required values as their default values in MySQL 5.7. Unfortunately the innodb_default_row_format option wasn't added until MySQL 5.7. Before 5.7, you have to add "row_format=dynamic" to the create table statements. Is it possible to construct different create table statements for MySQL vs Postgres? If so, then appending "row_format=dynamic" to MySQL create-table statements is an easy way to enable large-key support in MySQL 5.5 and 5.6 (along with setting the other three values). This would avoid having to reduce the keys sizes. |
Yes that is possible, it would also probably be the cleanest solution for now. |
Ok, what's the best way to do this? I see CreateSchemas functions in client/manager_sql, jwk_manager_sql, oauth2/consent_manager_sql and fosite_store_sql, and warden/group/manager_sql. I could make a function: customize(migrations, s.DB.DriverName()) that would customize the migrations depending upon the driver name, which would append "row_format=dynamic" if the driver looked like a mysql driver. What do you think? The same thing would have to be done for the ladon project as well, since it also creates tables. |
Yes that looks good. In ladon, we already separate between postgres and mysql so you would simply append the row_format there. For the other cases where the same schema is used it would be ok to have a helper function such as |
Ok, I'll draft a PR this weekend for your approval. |
Awesome! |
I'm closing this because it was added to the limitations section of the docs. It's unlikely that we'll change this. We don't have extensive foreign key relations which means that shortening private keys doesn't make a lot of sense (apart from this issue), as we always query the long ID. I think all cloud providers are on 5.7+ anyways today and there is a workaround for older installations which is documented in this issue. |
Debian bug https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=848603 is affecting Hydra, but should be fixable in the application.
When creating database table indexes are created as VARCHAR(255) fields, which usually should be well within the limit of 1000 bytes with the default latin1 encoding used by previous MySQL version's storage formats.
Debian maintainers made the questionable choice of setting the default string encoding to utf8mb4 (for emoji comments in WordPress or whatever), effectively quadrupling the storage size from 255 to 255*4 = 1020, which exceeds the pre-5.7 key size limit of 1000 bytes already. The limit was lowered to 767 bytes as well:
This results in the following
hydra host
error:FATA[0000] Could not create policy schema: Could not migrate sql schema, applied 0 migrations: Error 1071: Specified key was too long; max key length is 767 bytes handling 1
For
This is also discussed in https://stackoverflow.com/questions/6172798/mysql-varchar255-utf8-is-too-long-for-key-but-max-length-is-1000-bytes
Had Debian maintainers also opted to set
innodb_large_prefix=1
in their MySQL/MariaDB configuration, this would be fine (will be the default in the future). The documentation could hint at this to help users.What else can Hydra do? Set the charset for tables it creates to "
latin1
" .. which should be fine anyway.e.g.:
should work.
I've gone with a changed
db.opt
for my hydra database to force the use oflatin1
.*sigh*
The text was updated successfully, but these errors were encountered: