-- MySQL 8.0. Runtime fixes for the shared meeting_im database. -- Execute with a privileged account that can read hotgo.im_tenant. CREATE TABLE IF NOT EXISTS im_user_account_sequences ( tenant_id BIGINT NOT NULL, id TINYINT UNSIGNED NOT NULL, next_value INT UNSIGNED NOT NULL, updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (tenant_id, id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- If this table was created by the older independent-database script, its -- primary key may still be only (id). Shared DB must key by tenant_id too. ALTER TABLE im_user_account_sequences DROP PRIMARY KEY, ADD PRIMARY KEY (tenant_id, id); INSERT INTO im_user_account_sequences (tenant_id, id, next_value) SELECT tenant_id, 1, GREATEST(COALESCE(MAX(account_no), 999), 999) FROM im_users WHERE tenant_id > 0 GROUP BY tenant_id ON DUPLICATE KEY UPDATE next_value = GREATEST(next_value, VALUES(next_value)); INSERT IGNORE INTO im_user_account_sequences (tenant_id, id, next_value) SELECT id, 1, 999 FROM hotgo.im_tenant WHERE state = 1; DROP TABLE IF EXISTS im_login_lockouts; -- HTTP write idempotency is Redis-backed. Keep it out of MySQL. DROP TABLE IF EXISTS im_http_idempotency; DROP TABLE IF EXISTS im_group_idempotency; DROP TABLE IF EXISTS im_group_message_dedup; DROP TABLE IF EXISTS im_group_message_topic_shards; DROP TABLE IF EXISTS im_kafka_outbox; DROP TABLE IF EXISTS im_kafka_consume_log; DROP TABLE IF EXISTS im_business_events_outbox; DROP TABLE IF EXISTS im_group_events_outbox; DROP TABLE IF EXISTS im_login_failure_logs; DROP TABLE IF EXISTS im_action_tokens; -- User identity indexes must be unique inside one tenant, not globally. ALTER TABLE im_users DROP INDEX uk_im_users_account_no, DROP INDEX users_phone, DROP INDEX users_username, ADD UNIQUE INDEX uk_im_users_tenant_account_no (tenant_id, account_no), ADD UNIQUE INDEX uk_im_users_tenant_phone (tenant_id, phone), ADD UNIQUE INDEX uk_im_users_tenant_username (tenant_id, username); ALTER TABLE im_auth DROP INDEX auth_userid, ADD UNIQUE INDEX auth_tenant_userid (tenant_id, userid); -- Topic/subscription runtime indexes for shared-database deployments. -- These tables are on hot paths for topic lookup, message seq updates, -- unread calculation and subscription permission checks. Keep tenant_id as -- the leading column so one tenant does not scan another tenant's rows. SET @schema_name := DATABASE(); SET @sql := IF(( SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'im_topics' AND index_name = 'uk_topics_tenant_name' ) = 0, 'ALTER TABLE im_topics ADD UNIQUE INDEX uk_topics_tenant_name(tenant_id, name)', 'SELECT ''skip uk_topics_tenant_name'' AS status' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql := IF(( SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'im_topics' AND index_name = 'idx_topics_tenant_name_state_seqid' ) = 0, 'ALTER TABLE im_topics ADD INDEX idx_topics_tenant_name_state_seqid(tenant_id, name, state, seqid)', 'SELECT ''skip idx_topics_tenant_name_state_seqid'' AS status' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql := IF(( SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'im_topics' AND index_name = 'idx_topics_tenant_owner' ) = 0, 'ALTER TABLE im_topics ADD INDEX idx_topics_tenant_owner(tenant_id, owner)', 'SELECT ''skip idx_topics_tenant_owner'' AS status' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql := IF(( SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'im_subscriptions' AND index_name = 'idx_subscriptions_tenant_topic_deletedat' ) = 0, 'ALTER TABLE im_subscriptions ADD INDEX idx_subscriptions_tenant_topic_deletedat(tenant_id, topic, deletedat)', 'SELECT ''skip idx_subscriptions_tenant_topic_deletedat'' AS status' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @sql := IF(( SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'im_subscriptions' AND index_name = 'idx_subscriptions_tenant_user_topic_deletedat' ) = 0, 'ALTER TABLE im_subscriptions ADD INDEX idx_subscriptions_tenant_user_topic_deletedat(tenant_id, userid, topic, deletedat)', 'SELECT ''skip idx_subscriptions_tenant_user_topic_deletedat'' AS status' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- Default app release rows used by /v1/im/app/releases/latest. INSERT INTO hotgo.im_app_releases ( platform, channel, latest_version, min_supported_version, update_type, release_notes, remind_after_seconds ) VALUES ('ios', 'stable', '1.0.0', '1.0.0', 'none', '当前已是最新版本。', 0), ('android', 'stable', '1.0.0', '1.0.0', 'none', '当前已是最新版本。', 0), ('web', 'stable', '1.0.0', '1.0.0', 'none', '当前已是最新版本。', 0) ON DUPLICATE KEY UPDATE latest_version = VALUES(latest_version), min_supported_version = VALUES(min_supported_version), update_type = VALUES(update_type), release_notes = VALUES(release_notes), remind_after_seconds = VALUES(remind_after_seconds), updated_at = CURRENT_TIMESTAMP(3);