MySQL 5.7 上的存储过程语法无效,但适用于 MariaDB

Invalid stored procedure syntax on MySQL 5.7 but works on MariaDB

我正在尝试编写一个 MySQL 脚本来将管理员用户添加到服务器上的每个 WordPress 数据库并更新用户名中的用户信息已经存在。

我制作了以下脚本,它可以在 MariaDB 10.2.31 和 innodb_version 5.7.29 的服务器上运行,但它不能在 运行 MySQL Community Server 5.7 的服务器上运行.29,我收到一条错误消息:

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF EXISTS (SELECT * FROM cpaneluser_wp.wp_users WHERE user_login = 'newwpuser') THEN' at line 1

这是创建存储过程的脚本:

-- Create and update a WordPress administrator across all databases
USE mysql;

delimiter $$

DROP PROCEDURE IF EXISTS ensure_global_wp_user $$

CREATE PROCEDURE ensure_global_wp_user(
  IN username VARCHAR(255),
  IN email VARCHAR(255),
  IN password VARCHAR(255),
  IN nicename VARCHAR(255),
  IN displayname VARCHAR(255)
)
BEGIN

DECLARE current_schema VARCHAR(255);
DECLARE finished INTEGER DEFAULT 0;

DECLARE wp_schemas CURSOR FOR
  SELECT DISTINCT table_schema
    FROM INFORMATION_SCHEMA.tables
    WHERE table_name = 'wp_users';

DECLARE CONTINUE HANDLER
  FOR NOT FOUND
  SET finished = 1;

OPEN wp_schemas;

DROP TEMPORARY TABLE IF EXISTS exec_results;
CREATE TEMPORARY TABLE IF NOT EXISTS exec_results (
  username VARCHAR(255),
  dbname VARCHAR(255),
  action VARCHAR(255)
);

loopSchemas: LOOP
  FETCH wp_schemas INTO current_schema;
  IF finished = 1 THEN
    LEAVE loopSchemas;
  END IF;

  SET @expression = CONCAT("
    IF EXISTS (SELECT * FROM ",current_schema,".wp_users WHERE user_login = '",username,"') THEN
      UPDATE ",current_schema,".wp_users
        SET
          user_pass = MD5('",password,"'),
          user_email = '",email,"',
          user_nicename = '",nicename,"',
          display_name = '",displayname,"'
        WHERE user_login = '",username,"';
      INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','updated');
    ELSE
      INSERT INTO ",current_schema,".wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name, user_registered) VALUES
        ('",username,"', MD5('",password,"'), '",nicename,"', '",email,"', '0', '",displayname,"', NOW());
      SET @user_insert_id = LAST_INSERT_ID();
      INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
        (@user_insert_id, 'wp_capabilities', 'a:1:{s:13:\"administrator\";b:1;}');
      INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
        (@user_insert_id, 'wp_user_level', '10');
      INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','added');
    END IF;
  ");
  PREPARE stmt FROM @expression;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;

END LOOP loopSchemas;

CLOSE wp_schemas;

SELECT * FROM exec_results;

END $$

delimiter ;

你可以这样称呼它:

-- Create or update the newwpuser user on all wordpress databases
call ensure_global_wp_user('newwpuser', 'newwpuser@example.com', 'newpassword', 'newwpuser', 'newwpuser');

是否有不同的语法来实现此目的?我也尝试将 sql_mode 设置为 '',但没有任何区别。

您的@expression 在mysql.

中没有有效代码

试试这个,当然没有你的桌子我无法完全测试它

现在我首先通过另一个准备好的语句确定,如果用户存在,这个 returns 1 表示存在或 0 当 not.this 停在@res.

并使用它确定我应该使用和更新的方式,当存在时或不插入时。

Thbis 应该也可以在 mariadb 中使用。

DROP procedure IF EXISTS `ensure_global_wp_user`;

DELIMITER $$
USE `testdb`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `ensure_global_wp_user`(
  IN username VARCHAR(255),
  IN email VARCHAR(255),
  IN password VARCHAR(255),
  IN nicename VARCHAR(255),
  IN displayname VARCHAR(255)
)
BEGIN

DECLARE current_schema VARCHAR(255);
DECLARE finished INTEGER DEFAULT 0;

DECLARE wp_schemas CURSOR FOR
  SELECT DISTINCT table_schema
    FROM INFORMATION_SCHEMA.tables
    WHERE table_name = 'wp_users';

DECLARE CONTINUE HANDLER
  FOR NOT FOUND
  SET finished = 1;

OPEN wp_schemas;

DROP TEMPORARY TABLE IF EXISTS exec_results;
CREATE TEMPORARY TABLE IF NOT EXISTS exec_results (
  username VARCHAR(255),
  dbname VARCHAR(255),
  action VARCHAR(255)
);

loopSchemas: LOOP
  FETCH wp_schemas INTO current_schema;
  IF finished = 1 THEN
    LEAVE loopSchemas;
  END IF;
SET @sql = CONCAT("SELECT  EXISTS (SELECT * FROM ",current_schema,".wp_users WHERE user_login = '",username,"') INTO @res;");
  PREPARE stmt FROM @sql;
  EXECUTE stmt;

    IF @res = 1 THEN
      SET @expression = CONCAT("UPDATE ",current_schema,".wp_users
        SET
          user_pass = MD5('",password,"'),
          user_email = '",email,"',
          user_nicename = '",nicename,"',
          display_name = '",displayname,"'
        WHERE user_login = '",username,"';
      INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','updated');");
    ELSE
      SET @expression = CONCAT("INSERT INTO ",current_schema,".wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name, user_registered) VALUES
        ('",username,"', MD5('",password,"'), '",nicename,"', '",email,"', '0', '",displayname,"', NOW());
      SET @user_insert_id = LAST_INSERT_ID();
      INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
        (@user_insert_id, 'wp_capabilities', 'a:1:{s:13:\"administrator\";b:1;}');
      INSERT INTO ",current_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
        (@user_insert_id, 'wp_user_level', '10');
      INSERT INTO exec_results VALUES ('",username,"','",current_schema,"','added');");
    END IF;

  PREPARE stmt FROM @expression;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;

END LOOP loopSchemas;

CLOSE wp_schemas; 

SELECT * FROM exec_results;

END$$

DELIMITER ;

似乎根本问题在于 MySQL,与 MariaDB 不同,每次执行只需要 ONE 准备语句。

感谢 nbk 帮助分离 if 语句,我能够让它按如下方式工作:

USE mysql;

delimiter $$

DROP PROCEDURE IF EXISTS ensure_global_wp_user $$
CREATE PROCEDURE ensure_global_wp_user(
  IN username VARCHAR(255),
  IN email VARCHAR(255),
  IN password VARCHAR(255),
  IN nicename VARCHAR(255),
  IN displayname VARCHAR(255)
)
BEGIN

  DECLARE wp_schema VARCHAR(255);
  DECLARE finished INTEGER DEFAULT 0;

  DECLARE wp_schemas CURSOR FOR
    SELECT DISTINCT table_schema
      FROM INFORMATION_SCHEMA.tables
      WHERE table_name = 'wp_users';

  DECLARE CONTINUE HANDLER
    FOR NOT FOUND
    SET finished = 1;

  OPEN wp_schemas;

  DROP TEMPORARY TABLE IF EXISTS exec_results;
  CREATE TEMPORARY TABLE exec_results (
    username VARCHAR(255),
    dbname VARCHAR(255),
    action VARCHAR(255)
  );

  loopSchemas: LOOP
    FETCH wp_schemas INTO wp_schema;
    IF finished = 1 THEN
      LEAVE loopSchemas;
    END IF;

    SET @sql = CONCAT("
      SELECT EXISTS (
        SELECT *
          FROM ",wp_schema,".wp_users
          WHERE user_login = '",username,"'
      ) INTO @user_exists;");
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    IF @user_exists = 1 THEN
      SET @sql = CONCAT("
        UPDATE ",wp_schema,".wp_users
          SET
            user_pass = MD5('",password,"'),
            user_email = '",email,"',
            user_nicename = '",nicename,"',
            display_name = '",displayname,"'
          WHERE user_login = '",username,"';
      ");
      PREPARE stmt FROM @sql;
      EXECUTE stmt;
      DEALLOCATE PREPARE stmt;

      INSERT INTO exec_results VALUES (username, wp_schema, 'updated');
    ELSE
      SET @sql = CONCAT("
        INSERT INTO ",wp_schema,".wp_users (user_login, user_pass, user_nicename, user_email, user_status, display_name, user_registered) VALUES
          ('",username,"', MD5('",password,"'), '",nicename,"', '",email,"', '0', '",displayname,"', NOW());
      ");
      PREPARE stmt FROM @sql;
      EXECUTE stmt;
      DEALLOCATE PREPARE stmt;

      SET @user_insert_id = LAST_INSERT_ID();

      SET @sql = CONCAT("
        INSERT INTO ",wp_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
          (@user_insert_id, 'wp_capabilities', 'a:1:{s:13:\"administrator\";b:1;}');
      ");
      PREPARE stmt FROM @sql;
      EXECUTE stmt;
      DEALLOCATE PREPARE stmt;

      SET @sql = CONCAT("
        INSERT INTO ",wp_schema,".wp_usermeta (user_id, meta_key, meta_value) VALUES
          (@user_insert_id, 'wp_user_level', '10');
      ");
      PREPARE stmt FROM @sql;
      EXECUTE stmt;
      DEALLOCATE PREPARE stmt;

      INSERT INTO exec_results VALUES (username, wp_schema, 'added');
    END IF;

  END LOOP loopSchemas;

  CLOSE wp_schemas;

  SELECT * FROM exec_results;

END $$

delimiter ;