Description:
What did I do:
I have this View in the Database:
CREATE VIEW ldap_memberof
AS
SELECT userdb_person_group_maps.person_id AS person_id,
CONCAT('cn=', userdb_entities.dn, ',ou=groups,dc=example,dc=com') AS group_dn
FROM userdb_person_group_maps
INNER JOIN userdb_groups ON userdb_person_group_maps.group_id=userdb_groups.entity_id
INNER JOIN userdb_entities ON userdb_groups.entity_id=userdb_entities.id
WHERE userdb_groups.is_posix_group=TRUE
UNION
SELECT userdb_effective_person_permissions.person_id AS person_id,
CONCAT('cn=', userdb_effective_person_permissions.permission_name, ',cn=', userdb_account_types.name, ',ou=permissions,dc=example,dc=com') AS group_dn
FROM userdb_effective_person_permissions
INNER JOIN userdb_account_types ON userdb_effective_person_permissions.permission_type=userdb_account_types.id;
I dumped my Database with
"mysqldump --routines --events --opts > db.sql"
then recreated the Database:
mysql> DROP DATABASE utest;
mysql> CREATE DATABASE utest
mysql utest < db.sql
And finally I tried to accress the view:
mysql> SHOW CREATE VIEW ldap_memberof;
What did I expect:
I expected to see the view definition.
What happened:
I got this error message:
mysql> SHOW CREATE VIEW ldap_memberof;
ERROR 1271 (HY000): Illegal mix of collations for operation 'UNION'
How to repeat:
Use a Ubunut 12.04 Server 64bit (only tested this Distribution), and install mysql-server-5.5.
Then create the Database:
mysql> CREATE DATABASE utest
and add these tables and views:
CREATE TABLE userdb_entities (
id INTEGER NOT NULL AUTO_INCREMENT,
dn VARCHAR(100) NOT NULL UNIQUE,
type ENUM('person', 'group') NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) Engine=InnoDB, CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE userdb_persons (
entity_id INTEGER NOT NULL,
forename1 VARCHAR(45) NOT NULL,
forename2 VARCHAR(45),
surname VARCHAR(45) NOT NULL,
birthdate DATE,
ssha BINARY(38),
uid INTEGER,
gid INTEGER,
login_shell VARCHAR(45),
home_directory VARCHAR(45),
PRIMARY KEY (entity_id),
FOREIGN KEY (entity_id)
REFERENCES userdb_entities(id)
ON DELETE CASCADE ON UPDATE CASCADE
) Engine=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE userdb_groups (
entity_id INTEGER NOT NULL,
description VARCHAR(100),
is_posix_group BOOLEAN NOT NULL DEFAULT FALSE,
gid INTEGER,
PRIMARY KEY (entity_id),
FOREIGN KEY (entity_id)
REFERENCES userdb_entities(id)
ON DELETE CASCADE ON UPDATE CASCADE
) Engine=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE userdb_person_group_maps (
person_id INTEGER NOT NULL,
group_id INTEGER NOT NULL,
PRIMARY KEY (person_id, group_id),
FOREIGN KEY (person_id)
REFERENCES userdb_persons(entity_id)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (group_id)
REFERENCES userdb_groups(entity_id)
ON DELETE CASCADE ON UPDATE CASCADE
) Engine=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE userdb_account_types (
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(45) NOT NULL UNIQUE,
description VARCHAR(100),
PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE userdb_accounts (
person_id INTEGER NOT NULL,
type_id INTEGER NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
expiration_date DATE DEFAULT 0,
active BOOLEAN DEFAULT TRUE NOT NULL,
PRIMARY KEY (person_id, type_id),
FOREIGN KEY (person_id)
REFERENCES userdb_persons (entity_id)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (type_id)
REFERENCES userdb_account_types (id)
ON DELETE CASCADE ON UPDATE CASCADE
) Engine=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE userdb_permissions (
id INTEGER NOT NULL AUTO_INCREMENT,
type_id INTEGER NOT NULL,
name VARCHAR(20) NOT NULL UNIQUE,
description VARCHAR(100),
PRIMARY KEY (id),
FOREIGN KEY (type_id)
REFERENCES userdb_account_types (id)
ON DELETE CASCADE ON UPDATE CASCADE
) Engine=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE TABLE userdb_permission_entity_maps (
permission_id INTEGER NOT NULL,
entity_id INTEGER NOT NULL,
PRIMARY KEY (permission_id, entity_id),
FOREIGN KEY (permission_id)
REFERENCES userdb_permissions(id)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (entity_id)
REFERENCES userdb_entities(id)
ON DELETE CASCADE ON UPDATE CASCADE
) Engine=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CREATE VIEW userdb_effective_person_permissions
AS
SELECT userdb_entities.id AS person_id,
userdb_entities.dn AS person_dn,
userdb_permissions.id AS permission_id,
userdb_permissions.name AS permission_name,
userdb_permissions.type_id AS permission_type
FROM userdb_entities
INNER JOIN userdb_permission_entity_maps ON userdb_entities.id=userdb_permission_entity_maps.entity_id
INNER JOIN userdb_permissions ON userdb_permission_entity_maps.permission_id=userdb_permissions.id
INNER JOIN userdb_persons ON userdb_entities.id=userdb_persons.entity_id
INNER JOIN userdb_accounts ON userdb_persons.entity_id=userdb_accounts.person_id
WHERE userdb_entities.type='person'
AND userdb_permissions.type_id=userdb_accounts.type_id
AND userdb_accounts.active=TRUE
AND (userdb_accounts.expiration_date>NOW() OR userdb_accounts.expiration_date=0)
UNION
SELECT person_entities.id AS person_id,
person_entities.dn AS person_dn,
userdb_permissions.id AS permission_id,
userdb_permissions.name AS permission_name,
userdb_permissions.type_id AS permission_type
FROM userdb_entities AS person_entities
INNER JOIN userdb_persons ON person_entities.id=userdb_persons.entity_id
INNER JOIN userdb_person_group_maps ON userdb_persons.entity_id=userdb_person_group_maps.person_id
INNER JOIN userdb_groups ON userdb_person_group_maps.group_id=userdb_groups.entity_id
INNER JOIN userdb_entities AS group_entities ON userdb_groups.entity_id=group_entities.id
INNER JOIN userdb_permission_entity_maps ON group_entities.id=userdb_permission_entity_maps.entity_id
INNER JOIN userdb_permissions ON userdb_permission_entity_maps.permission_id=userdb_permissions.id
INNER JOIN userdb_accounts ON userdb_persons.entity_id=userdb_accounts.person_id
WHERE userdb_permissions.type_id=userdb_accounts.type_id
AND userdb_accounts.active=TRUE
AND (userdb_accounts.expiration_date>NOW() OR userdb_accounts.expiration_date=0);
CREATE VIEW ldap_memberof
AS
SELECT userdb_person_group_maps.person_id AS person_id,
CONCAT('cn=', userdb_entities.dn, ',ou=groups,dc=example,dc=com') AS group_dn
FROM userdb_person_group_maps
INNER JOIN userdb_groups ON userdb_person_group_maps.group_id=userdb_groups.entity_id
INNER JOIN userdb_entities ON userdb_groups.entity_id=userdb_entities.id
WHERE userdb_groups.is_posix_group=TRUE
UNION
SELECT userdb_effective_person_permissions.person_id AS person_id,
CONCAT('cn=', userdb_effective_person_permissions.permission_name, ',cn=', userdb_account_types.name, ',ou=permissions,dc=example,dc=com') AS group_dn
FROM userdb_effective_person_permissions
INNER JOIN userdb_account_types ON userdb_effective_person_permissions.permission_type=userdb_account_types.id;
Then dump it all, recreate the database and replay the dump:
"mysqldump --routines --events --opts > db.sql"
mysql> DROP DATABASE utest;
mysql> CREATE DATABASE utest
mysql utest < db.sql
and try to access the view "ldap_memberof":
mysql> SHOW CREATE VIEW ldap_memberof;
Suggested fix:
I found two kinds of workarounds:
1. Rewrite the view, so that it doesn't reference another view:
CREATE VIEW ldap_memberof
AS
SELECT userdb_person_group_maps.person_id AS person_id,
CONCAT('cn=', userdb_entities.dn, ',ou=groups,dc=example,dc=com') AS group_dn
FROM userdb_person_group_maps
INNER JOIN userdb_groups ON userdb_person_group_maps.group_id=userdb_groups.entity_id
INNER JOIN userdb_entities ON userdb_groups.entity_id=userdb_entities.id
WHERE userdb_groups.is_posix_group=TRUE
UNION
SELECT userdb_entities.id AS person_id,
CONCAT('cn=', userdb_permissions.name, ',cn=', userdb_account_types.name, ',ou=permissions,dc=example,dc=com') AS group_dn
FROM userdb_entities
INNER JOIN userdb_permission_entity_maps ON userdb_entities.id=userdb_permission_entity_maps.entity_id
INNER JOIN userdb_permissions ON userdb_permission_entity_maps.permission_id=userdb_permissions.id
INNER JOIN userdb_persons ON userdb_entities.id=userdb_persons.entity_id
INNER JOIN userdb_accounts ON userdb_persons.entity_id=userdb_accounts.person_id
INNER JOIN userdb_account_types ON userdb_accounts.type_id=userdb_account_types.id
WHERE userdb_entities.type='person'
AND userdb_permissions.type_id=userdb_accounts.type_id
AND userdb_accounts.active=TRUE
AND (userdb_accounts.expiration_date>NOW() OR userdb_accounts.expiration_date=0)
UNION
SELECT person_entities.id AS person_id,
CONCAT('cn=', userdb_permissions.name, ',cn=', userdb_account_types.name, ',ou=permissions,dc=example,dc=com') AS group_dn
FROM userdb_entities AS person_entities
INNER JOIN userdb_persons ON person_entities.id=userdb_persons.entity_id
INNER JOIN userdb_person_group_maps ON userdb_persons.entity_id=userdb_person_group_maps.person_id
INNER JOIN userdb_groups ON userdb_person_group_maps.group_id=userdb_groups.entity_id
INNER JOIN userdb_entities AS group_entities ON userdb_groups.entity_id=group_entities.id
INNER JOIN userdb_permission_entity_maps ON group_entities.id=userdb_permission_entity_maps.entity_id
INNER JOIN userdb_permissions ON userdb_permission_entity_maps.permission_id=userdb_permissions.id
INNER JOIN userdb_accounts ON userdb_persons.entity_id=userdb_accounts.person_id
INNER JOIN userdb_account_types ON userdb_accounts.type_id=userdb_account_types.id
WHERE userdb_permissions.type_id=userdb_accounts.type_id
AND userdb_accounts.active=TRUE
AND (userdb_accounts.expiration_date>NOW() OR userdb_accounts.expiration_date=0);
2. Change collation on all underlying tables to utf8_general_ci:
ALTER TABLE userdb_account_types CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE userdb_accounts CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE userdb_entities CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE userdb_groups CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE userdb_permission_entity_maps CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE userdb_permissions CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE userdb_person_group_maps CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE userdb_persons CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;